[mod] typification of SearXNG: add new result type Video (#6743)

- Python class:   searx/result_types/video.py
- Jinja template: searx/templates/simple/result_templates/videos.html
- CSS (less)      client/simple/src/less/result_types/video.less

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser
2026-09-20 16:12:32 +02:00
committed by Markus Heiser
parent fdd8525b1a
commit e40de2d992
9 changed files with 87 additions and 63 deletions

View File

@@ -0,0 +1,25 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
Layout of the Video result class
*/
.result-videos {
a.thumbnail_link {
.ltr-float-left();
.ltr-margin-right(1rem);
.ltr-margin-left(0);
width: 10rem !important;
aspect-ratio: 16 / 9 !important;
}
.content {
overflow: hidden;
}
.embedded-video iframe {
width: 100%;
aspect-ratio: 16 / 9;
padding: 10px 0 0 0;
}
}

View File

@@ -431,34 +431,6 @@ article[data-vim-selected].category-social {
padding: 10px 0 0 0;
}
.result-videos {
a.thumbnail_link {
.ltr-float-left();
.ltr-margin-right(1rem);
.ltr-margin-left(0);
width: 10rem !important;
aspect-ratio: 16 / 9 !important;
}
.content {
overflow: hidden;
}
.embedded-video iframe {
width: 100%;
aspect-ratio: 16 / 9;
padding: 10px 0 0 0;
}
}
@supports not (aspect-ratio: 1 / 1) {
// support older browsers which do not have aspect-ratio
// https://caniuse.com/?search=aspect-ratio
.result-videos .embedded-video iframe {
height: calc(@results-width * 9 / 16);
}
}
.engines {
.ltr-float-right();
clear: both;

View File

@@ -0,0 +1,7 @@
.. _result_types.video:
=============
Video Results
=============
.. automodule:: searx.result_types.video

View File

@@ -19,13 +19,13 @@ following types have been implemented so far ..
main/paper
main/file
main/image
main/video
The :ref:`LegacyResult <LegacyResult>` is used internally for the results that
have not yet been typed. The templates can be used as orientation until the
final typing is complete.
- :ref:`template default` / :py:obj:`Result`
- :ref:`template videos`
- :ref:`template torrent`
- :ref:`template map`
- :ref:`template packages`

View File

@@ -129,29 +129,6 @@ audio_src : uri,
URL of an embedded ``<audio controls>``.
.. _template videos:
``videos.html``
---------------
Displays result fields from:
- :ref:`macro result_header` and
- :ref:`macro result_sub_header`
Additional fields used in the :origin:`videos.html
<searx/templates/simple/result_templates/videos.html>`:
iframe_src : :py:class:`str`
URL of an embedded ``<iframe>`` / the frame is collapsible.
The videos are displayed as small thumbnails in the main results list, there
is an additional button to collaps/open the embeded video.
content : :py:class:`str`
Description of the code fragment.
.. _template torrent:
``torrent.html``

View File

@@ -28,6 +28,7 @@ __all__ = [
"File",
"Image",
"ImageRef",
"Video",
]
import typing as t
@@ -40,6 +41,7 @@ from .code import Code
from .paper import Paper
from .file import File
from .image import Image, ImageRef
from .video import Video
class ResultList(list[Result | LegacyResult], abc.ABC):
@@ -56,6 +58,7 @@ class ResultList(list[Result | LegacyResult], abc.ABC):
Paper = Paper
File = File
Image = Image
Video = Video
MainResult = MainResult
Result = Result
Translations = Translations

View File

@@ -31,7 +31,6 @@ from collections.abc import Callable
import msgspec
from searx import logger
from searx.utils import get_embedded_stream_url
log = logger.getChild("result_types")
@@ -386,7 +385,11 @@ class MainResult(Result): # pylint: disable=missing-class-docstring
"""URL of a image that is displayed in the result item."""
iframe_src: str = ""
"""URL of an embedded ``<iframe>`` / the frame is collapsible."""
"""URL of an embedded ``<iframe>`` / the frame is collapsible.
To convert a standard video URL from a widely know video services into its
embed format, have a look at :obj:`searx.utils.get_embedded_stream_url`.
"""
audio_src: str = ""
"""URL of an embedded ``<audio controls>``."""
@@ -542,10 +545,6 @@ class LegacyResult(dict[str, t.Any]):
DeprecationWarning,
)
# TODO: move into typed video results class once it is implemented # pylint: disable=fixme
if self.template == "videos.html" and self.url and not self.iframe_src:
self.iframe_src = get_embedded_stream_url(self.url)
def __getattr__(self, name: str, default: t.Any = UNSET) -> t.Any:
if default == UNSET and name not in self:
raise AttributeError(f"LegacyResult object has no field named: {name}")

View File

@@ -0,0 +1,30 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Typification of the *video* results. Results of this type are rendered in
the :origin:`videos.html <searx/templates/simple/result_templates/videos.html>`
template.
.. autoclass:: Video
:members:
:show-inheritance:
"""
# pylint: disable=too-few-public-methods
__all__ = ["Video"]
import typing as t
from searx.utils import get_embedded_stream_url
from ._base import MainResult
@t.final
class Video(MainResult, kw_only=True):
"""Result type suitable for displaying videos."""
template: str = "videos.html"
def __post_init__(self):
super().__post_init__()
if self.url and not self.iframe_src:
self.iframe_src = get_embedded_stream_url(self.url)

View File

@@ -593,13 +593,24 @@ def eval_xpath_getindex(
return default
def get_embedded_stream_url(url: str):
"""
Converts a standard video URL into its embed format. Supported services include Youtube,
Facebook, Instagram, TikTok, Dailymotion, and Bilibili.
def get_embedded_stream_url(url: str) -> str:
"""Converts a standard video URL into its embed format.
Supported services include:
- Youtube
- Facebook
- Instagram
- TikTok
- Dailymotion
- Bilibili
The function is suitable for the field :obj:`MainResult.iframe_src
<searx.result_types.MainResult.iframe_src>`. If ``url`` is not from one of
the supported services, an empty string is returned.
"""
parsed_url = urlparse(url)
iframe_src = None
iframe_src = ""
# YouTube
if parsed_url.netloc in ['www.youtube.com', 'youtube.com'] and parsed_url.path == '/watch' and parsed_url.query: