diff options
| author | Markus Heiser <markus.heiser@darmarit.de> | 2025-10-13 09:28:42 +0200 |
|---|---|---|
| committer | Markus Heiser <markus.heiser@darmarIT.de> | 2025-10-20 10:18:33 +0200 |
| commit | 937165853185ca16b0da6f72bc42bd1487ea0dcb (patch) | |
| tree | 70da1dce7cb51d0f59cd36392103e8f33318f379 /searx/result_types | |
| parent | ee6d4f322f4bda18759ffb99380a06923424695b (diff) | |
[mod] typification of SearXNG: add new result type File
This PR adds a new result type: File
Python class: searx/result_types/file.py
Jinja template: searx/templates/simple/result_templates/file.html
CSS (less) client/simple/src/less/result_types/file.less
Class 'File' (singular) replaces template 'files.html' (plural). The renaming
was carried out because there is only one file (singular) in a result. Not to be
confused with the category 'files' where in multiple results can exist.
As mentioned in issue [1], the class '.category-files' was removed from the CSS
and the stylesheet was adopted in result_types/file.less (there based on the
templates and no longer based on the category).
[1] https://github.com/searxng/searxng/issues/5198
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
Diffstat (limited to 'searx/result_types')
| -rw-r--r-- | searx/result_types/__init__.py | 3 | ||||
| -rw-r--r-- | searx/result_types/_base.py | 23 | ||||
| -rw-r--r-- | searx/result_types/file.py | 94 |
3 files changed, 111 insertions, 9 deletions
diff --git a/searx/result_types/__init__.py b/searx/result_types/__init__.py index a1976c10f..4ae2de816 100644 --- a/searx/result_types/__init__.py +++ b/searx/result_types/__init__.py @@ -23,6 +23,7 @@ __all__ = [ "WeatherAnswer", "Code", "Paper", + "File", ] import typing as t @@ -33,6 +34,7 @@ from .answer import AnswerSet, Answer, Translations, WeatherAnswer from .keyvalue import KeyValue from .code import Code from .paper import Paper +from .file import File class ResultList(list[Result | LegacyResult], abc.ABC): @@ -47,6 +49,7 @@ class ResultList(list[Result | LegacyResult], abc.ABC): KeyValue = KeyValue Code = Code Paper = Paper + File = File MainResult = MainResult Result = Result Translations = Translations diff --git a/searx/result_types/_base.py b/searx/result_types/_base.py index e97894b75..ffcf7f143 100644 --- a/searx/result_types/_base.py +++ b/searx/result_types/_base.py @@ -27,7 +27,6 @@ import typing as t import re import urllib.parse import warnings -import time import datetime from collections.abc import Callable @@ -236,13 +235,6 @@ class Result(msgspec.Struct, kw_only=True): url: str | None = None """A link related to this *result*""" - template: str = "default.html" - """Name of the template used to render the result. - - By default :origin:`result_templates/default.html - <searx/templates/simple/result_templates/default.html>` is used. - """ - engine: str | None = "" """Name of the engine *this* result comes from. In case of *plugins* a prefix ``plugin:`` is set, in case of *answerer* prefix ``answerer:`` is @@ -350,6 +342,13 @@ class Result(msgspec.Struct, kw_only=True): class MainResult(Result): # pylint: disable=missing-class-docstring """Base class of all result types displayed in :ref:`area main results`.""" + template: str = "default.html" + """Name of the template used to render the result. + + By default :origin:`result_templates/default.html + <searx/templates/simple/result_templates/default.html>` is used. + """ + title: str = "" """Link title of the result item.""" @@ -359,6 +358,12 @@ class MainResult(Result): # pylint: disable=missing-class-docstring img_src: str = "" """URL of a image that is displayed in the result item.""" + iframe_src: str = "" + """URL of an embedded ``<iframe>`` / the frame is collapsible.""" + + audio_src: str = "" + """URL of an embedded ``<audio controls>``.""" + thumbnail: str = "" """URL of a thumbnail that is displayed in the result item.""" @@ -372,7 +377,7 @@ class MainResult(Result): # pylint: disable=missing-class-docstring completely eliminated. """ - length: time.struct_time | None = None + length: datetime.timedelta | None = None """Playing duration in seconds.""" views: str = "" diff --git a/searx/result_types/file.py b/searx/result_types/file.py new file mode 100644 index 000000000..5b58116c2 --- /dev/null +++ b/searx/result_types/file.py @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +""" +Typification of the *file* results. Results of this type are rendered in +the :origin:`file.html <searx/templates/simple/result_templates/file.html>` +template. + +---- + +.. autoclass:: File + :members: + :show-inheritance: + +""" +# pylint: disable=too-few-public-methods + + +__all__ = ["File"] + +import typing as t +import mimetypes + +from ._base import MainResult + + +@t.final +class File(MainResult, kw_only=True): + """Class for results of type *file*""" + + template: str = "file.html" + + filename: str = "" + """Name of the file.""" + + size: str = "" + """Size of bytes in human readable notation (``MB`` for 1024 * 1024 Bytes + file size.)""" + + time: str = "" + """Indication of a time, such as the date of the last modification or the + date of creation. This is a simple string, the *date* of which can be freely + chosen according to the context.""" + + mimetype: str = "" + """Mimetype/Subtype of the file. For ``audio`` and ``video``, a URL can be + passed in the :py:obj:`File.embedded` field to embed the referenced media in + the result. If no value is specified, the MIME type is determined from + ``self.filename`` or, alternatively, from ``self.embedded`` (if either of + the two values is set).""" + + abstract: str = "" + """Abstract of the file.""" + + author: str = "" + """Author of the file.""" + + embedded: str = "" + """URL of an embedded media type (audio or video) / is collapsible.""" + + mtype: str = "" + """Used for displaying :py:obj:`File.embedded`. Its value is automatically + populated from the base type of :py:obj:`File.mimetype`, and can be + explicitly set to enforce e.g. ``audio`` or ``video`` when mimetype is + something like "application/ogg" but its know the content is for example a + video.""" + + subtype: str = "" + """Used for displaying :py:obj:`File.embedded`. Its value is automatically + populated from the subtype type of :py:obj:`File.mimetype`, and can be + explicitly set to enforce a subtype for the :py:obj:`File.embedded` + element.""" + + def __post_init__(self): + super().__post_init__() + + if not self.mtype or not self.subtype: + + fn = self.filename or self.embedded + if not self.mimetype and fn: + self.mimetype = mimetypes.guess_type(fn, strict=False)[0] or "" + + mtype, subtype = (self.mimetype.split("/", 1) + [""])[:2] + + if not self.mtype: + # I don't know why, but the ogg video stream is not displayed, + # may https://github.com/videojs/video.js can help? + if self.embedded.endswith(".ogv"): + self.mtype = "video" + elif self.embedded.endswith(".oga"): + self.mtype = "audio" + else: + self.mtype = mtype + + if not self.subtype: + self.subtype = subtype |