[mod] image results: add list of alternative formats (#6153)

* [mod] template images.html: reformatted for readability (no func change)

In preparation for upcoming changes, the template is being reformatted for
better readability; no functional changes are being made.

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>

* [mod] image results: add list of alternative formats

To test alternatives formats apply patch from below, query ``!flaticon bmw`` and
open the detail view for the image.

    diff --git a/searx/engines/flaticon.py b/searx/engines/flaticon.py
    index 06b6a8e25..d88388705 100644
    --- a/searx/engines/flaticon.py
    +++ b/searx/engines/flaticon.py
    @@ -8,7 +8,7 @@ from urllib.parse import urlencode

     import typing as t

    -from searx.result_types import EngineResults
    +from searx.result_types import EngineResults, ImageRef

     if t.TYPE_CHECKING:
         from searx.extended_types import SXNG_Response
    @@ -61,6 +61,14 @@ def response(resp: "SXNG_Response"):
                     thumbnail_src=_fix_url(result["png"]),
                     img_src=_fix_url(result["png512"]),
                     author=result["team_name"],
    +                formats=[
    +                    ImageRef(label="PNG 100x100", url="https://example.org/test.png", subtype="png"),
    +                    ImageRef(label="SVG", url="https://example.org/test.svg", subtype="svg+xml"),
    +                    ImageRef(url="https://example.org/test.jpg", subtype="jpeg"),
    +                    ImageRef(url="https://example.org/test.bmp", subtype="bmp"),
    +                    ImageRef(url="https://example.org/test.ico", subtype="x-icon"),
    +                    ImageRef(url="https://example.org/test.tif", subtype="tiff"),
    +                ],
                 )
             )

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>

---------

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser
2026-06-13 13:28:05 +02:00
committed by GitHub
parent b48205b384
commit e3bd7f5df1
5 changed files with 142 additions and 32 deletions
+1
View File
@@ -63,6 +63,7 @@ def response(resp: "SXNG_Response"):
url=_fix_url(result["slug"]), url=_fix_url(result["slug"]),
thumbnail_src=_fix_url(result["png"]), thumbnail_src=_fix_url(result["png"]),
img_src=_fix_url(result["png512"]), img_src=_fix_url(result["png512"]),
img_format="PNG",
author=result["team_name"], author=result["team_name"],
) )
) )
+4 -1
View File
@@ -382,6 +382,9 @@ def _get_image_result(result) -> dict[str, t.Any] | None:
size_str = "".join(filter(str.isdigit, result["filesize"])) size_str = "".join(filter(str.isdigit, result["filesize"]))
filesize = humanize_bytes(int(size_str)) filesize = humanize_bytes(int(size_str))
img_format = result.get("format").upper()
if img_format == "UNKNOWN":
img_format = ""
return { return {
"template": "images.html", "template": "images.html",
"url": url, "url": url,
@@ -390,7 +393,7 @@ def _get_image_result(result) -> dict[str, t.Any] | None:
"img_src": result.get("rawImageUrl"), "img_src": result.get("rawImageUrl"),
"thumbnail_src": thumbnailUrl, "thumbnail_src": thumbnailUrl,
"resolution": resolution, "resolution": resolution,
"img_format": result.get("format"), "img_format": img_format,
"filesize": filesize, "filesize": filesize,
} }
+3 -1
View File
@@ -24,6 +24,8 @@ __all__ = [
"Code", "Code",
"Paper", "Paper",
"File", "File",
"Image",
"ImageRef",
] ]
import typing as t import typing as t
@@ -35,7 +37,7 @@ from .keyvalue import KeyValue
from .code import Code from .code import Code
from .paper import Paper from .paper import Paper
from .file import File from .file import File
from .image import Image from .image import Image, ImageRef
class ResultList(list[Result | LegacyResult], abc.ABC): class ResultList(list[Result | LegacyResult], abc.ABC):
+66 -3
View File
@@ -7,14 +7,51 @@ template.
:members: :members:
:show-inheritance: :show-inheritance:
.. autoclass:: ImageRef
:members:
""" """
# pylint: disable=too-few-public-methods
__all__ = ["Image", "ImageRef"]
__all__ = ["Image"] import types
import typing as t import typing as t
from collections.abc import Callable
import msgspec
from ._base import MainResult, Result, log, LegacyResult
MimeSubType = t.Literal["png", "svg+xml", "jpeg", "bmp", "x-icon", "tiff"]
MIMESUB: dict[MimeSubType, str] = {
"png": "PNG",
"svg+xml": "SVG",
"jpeg": "JPG",
"bmp": "BMP",
"x-icon": "ICO",
"tiff": "TIF",
}
from ._base import MainResult class ImageRef(msgspec.Struct, kw_only=True):
"""Reference to an (alternative) image format"""
url: str
"""URL of the image reference."""
subtype: MimeSubType
"""Subtype (mimetype) of the image format."""
label: str = ""
"""Label of the reference, default is build from the uppercase of
:py:obj:`Image.ImageRef.subtype`."""
mtype: t.Literal["image"] = "image"
def __post_init__(self):
if not self.label:
self.label = MIMESUB.get(self.subtype, self.subtype.upper())
@t.final @t.final
@@ -42,3 +79,29 @@ class Image(MainResult, kw_only=True):
filesize: str = "" filesize: str = ""
"""Size of bytes in :py:obj:`human readable <searx.humanize_bytes>` notation """Size of bytes in :py:obj:`human readable <searx.humanize_bytes>` notation
(e.g. ``1MB`` for ``1024*1024`` Bytes filesize).""" (e.g. ``1MB`` for ``1024*1024`` Bytes filesize)."""
formats: list[ImageRef] = []
"""List of links to alternative image formats."""
def filter_urls(self, filter_func: "Callable[[Result | LegacyResult, str, str], str | bool ]"):
for _ref in self.formats[:]:
_name = f"Image.formats:{_ref.label}"
try:
_url = filter_func(self, _name, _ref.url)
except Exception as exc: # pylint: disable=broad-exception-caught
# pylint: disable=no-member
_tb: types.TracebackType = exc.__traceback__.tb_next.tb_next # type: ignore
_fn = _tb.tb_frame.f_code.co_filename
_lno = _tb.tb_lineno
log.error("filter_urls: [%s] ignore %s from callback %s:%s", _name, repr(exc), _fn, _lno)
continue
if isinstance(_url, str):
log.debug("filter_urls: [%s] URL %s -> %s", _name, _ref.url, _url)
_ref.url = _url
elif not _url:
log.debug("filter_urls: [%s] drop ref %s", _name, _ref)
self.formats.remove(_ref)
return super().filter_urls(filter_func)
@@ -1,28 +1,69 @@
<article class="result result-images {% if result['category'] %}category-{{ result['category'] }}{% endif %}">{{- "" -}} {% macro _target(url, new_tab=False) -%}
<a {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} href="{{ result.img_src }}">{{- "" -}} {%- if new_tab %} target="_blank" rel="noopener noreferrer"
<img class="image_thumbnail" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} src="{% if result.thumbnail_src %}{{ image_proxify(result.thumbnail_src) }}{% else %}{{ image_proxify(result.img_src) }}{% endif %}" alt="{{ result.title|striptags }}" loading="lazy" width="200" height="200">{{- "" -}} {%- else %} rel="noreferrer"
{%- if result.resolution %} <span class="image_resolution">{{ result.resolution }}</span> {%- endif -%} {%- endif %}
<span class="title">{{ result.title|striptags }}</span>{{- "" -}} {%- endmacro %}
<span class="source">{{- result.parsed_url.netloc -}}</span>{{- "" -}}
</a>{{- "" -}} {% macro _label(label, value) -%}
<div class="detail swipe-horizontal">{{- "" -}} {%- if value -%}<span>{{ label }}:</span>{{ value }}
<a class="result-detail-close" href="#">{{ icon('close') }}</a>{{- "" -}} {%- else %} &nbsp;
<a class="result-detail-previous" href="#">{{ icon('navigate-left') }}</a>{{- "" -}} {%- endif -%}
<a class="result-detail-next" href="#">{{ icon('navigate-right') }}</a>{{- "" -}} {%- endmacro %}
<a class="result-images-source" {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} href="{{ result.img_src }}">
<img src="" data-src="{{ image_proxify(result.img_src) }}" alt="{{ result.title|striptags }}">{{- "" -}} <article class="result result-images
</a>{{- "" -}} {%- if result["category"] %} category-{{ result["category"] }}
<div class="result-images-labels">{{- "" -}} {%- endif -%}"
<h4>{{ result.title|striptags }}</h4>{{- "" -}} >
<p class="result-content">{%- if result.content %}{{ result.content|striptags }}{% else %}&nbsp;{% endif -%}</p>{{- "" -}} <a {{ _target(results_on_new_tab) }} href="{{ result.img_src }}">
<hr>{{- "" -}} <img class="image_thumbnail" {{ _target(results_on_new_tab) }}
<p class="result-author">{%- if result.author %}<span>{{ _('Author') }}:</span>{{ result.author|striptags }}{% else %}&nbsp;{% endif -%}</p>{{- "" -}} src="
<p class="result-resolution">{%- if result.resolution %}<span>{{ _('Resolution') }}:</span>{{ result.resolution }}{% else %}&nbsp;{% endif -%}</p>{{- "" -}} {%- if result.thumbnail_src -%}
<p class="result-format">{%- if result.img_format %}<span>{{ _('Format') }}:</span>{{ result.img_format }}{% else %}&nbsp;{% endif -%}</p>{{- "" -}} {{ image_proxify(result.thumbnail_src) }}
<p class="result-filesize">{%- if result.filesize %}<span>{{ _('Filesize') }}:</span>{{ result.filesize}}{% else %}&nbsp;{% endif -%}</p>{{- "" -}} {%- else -%}
<p class="result-source">{%- if result.source %}<span>{{ _('Source') }}:</span>{{ result.source }}{% else %}&nbsp;{% endif -%}</p>{{- "" -}} {{ image_proxify(result.img_src) }}
<p class="result-engine"><span>{{ _('Engine') }}:</span>{{ result.engine }}</p>{{- "" -}}{{- "" -}} {%- endif -%}
<p class="result-url"><span>{{ _('View source') }}:</span><a {% if results_on_new_tab %}target="_blank" rel="noopener noreferrer"{% else %}rel="noreferrer"{% endif %} href="{{ result.url }}">{{ result.url }}</a></p>{{- "" -}} "
</div>{{- "" -}} alt="{{ result.title | striptags }}" loading="lazy" width="200" height="200"
</div>{{- "" -}} {{- "" -}}
>
{%- if result.resolution %}
<span class="image_resolution">{{ result.resolution }}</span>
{%- endif -%}
<span class="title">{{ result.title | striptags }}</span>
<span class="source">{{- result.parsed_url.netloc -}}</span>
</a>
<div class="detail swipe-horizontal">
<a class="result-detail-close" href="#">{{ icon("close") }}</a>
<a class="result-detail-previous" href="#">{{ icon("navigate-left") }}</a>
<a class="result-detail-next" href="#">{{ icon("navigate-right") }}</a>
<a class="result-images-source" {{ _target(results_on_new_tab) }} href="{{ result.img_src }}">
<img src=""
data-src="{{ image_proxify(result.img_src) }}"
alt="{{ result.title | striptags }}">
</a>
<div class="result-images-labels">
<h4>{{ result.title | striptags }}</h4>
<p class="result-content">
{%- if result.content %} {{ result.content | striptags }}
{%- else %} &nbsp;
{%- endif -%}
</p>
<hr>
<p class="result-author">{{ _label(_("Author"), result.author) }}</p>
<p class="result-resolution">{{ _label(_("Resolution"), result.resolution) }}</p>
<p class="result-format">
<span>{{ _("Image formats") }}:</span>
{{- "" -}}<a {{ _target(results_on_new_tab) }} href="{{ result.img_src }}">{{- result.img_format or _("original format") -}}</a>
{%- for ref in result.formats -%}
&nbsp;| <a {{ _target(results_on_new_tab) }} href="{{ ref.url }}">{{ ref.label }}</a>
{%- endfor %}
</p>
<p class="result-filesize">{{ _label(_("Filesize"), result.filesize) }}</p>
<p class="result-source">{{ _label(_("Source"), result.source) }}</p>
<p class="result-engine">{{ _label(_("Engine"), result.engine) }}</p>
<p class="result-url"><span>{{ _("View source") }}:</span>{{- "" -}}
<a {{ _target(results_on_new_tab) }} href="{{ result.url }}">{{ result.url }}</a>
</p>
</div>
</div>
</article> </article>