mirror of
https://github.com/searxng/searxng.git
synced 2026-06-14 22:06:52 +02:00
[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:
@@ -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"],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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 %}
|
||||||
<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 %} {% 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 %} {% endif -%}</p>{{- "" -}}
|
src="
|
||||||
<p class="result-resolution">{%- if result.resolution %}<span>{{ _('Resolution') }}:</span>{{ result.resolution }}{% else %} {% endif -%}</p>{{- "" -}}
|
{%- if result.thumbnail_src -%}
|
||||||
<p class="result-format">{%- if result.img_format %}<span>{{ _('Format') }}:</span>{{ result.img_format }}{% else %} {% endif -%}</p>{{- "" -}}
|
{{ image_proxify(result.thumbnail_src) }}
|
||||||
<p class="result-filesize">{%- if result.filesize %}<span>{{ _('Filesize') }}:</span>{{ result.filesize}}{% else %} {% endif -%}</p>{{- "" -}}
|
{%- else -%}
|
||||||
<p class="result-source">{%- if result.source %}<span>{{ _('Source') }}:</span>{{ result.source }}{% else %} {% 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 %}
|
||||||
|
{%- 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 -%}
|
||||||
|
| <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>
|
||||||
|
|||||||
Reference in New Issue
Block a user