[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

@@ -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: