mirror of
https://github.com/searxng/searxng.git
synced 2026-09-23 06:36:12 +00:00
[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:
committed by
Markus Heiser
parent
fdd8525b1a
commit
e40de2d992
25
client/simple/src/less/result_types/video.less
Normal file
25
client/simple/src/less/result_types/video.less
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -431,34 +431,6 @@ article[data-vim-selected].category-social {
|
|||||||
padding: 10px 0 0 0;
|
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 {
|
.engines {
|
||||||
.ltr-float-right();
|
.ltr-float-right();
|
||||||
clear: both;
|
clear: both;
|
||||||
|
|||||||
7
docs/dev/result_types/main/video.rst
Normal file
7
docs/dev/result_types/main/video.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.. _result_types.video:
|
||||||
|
|
||||||
|
=============
|
||||||
|
Video Results
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. automodule:: searx.result_types.video
|
||||||
@@ -19,13 +19,13 @@ following types have been implemented so far ..
|
|||||||
main/paper
|
main/paper
|
||||||
main/file
|
main/file
|
||||||
main/image
|
main/image
|
||||||
|
main/video
|
||||||
|
|
||||||
The :ref:`LegacyResult <LegacyResult>` is used internally for the results that
|
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
|
have not yet been typed. The templates can be used as orientation until the
|
||||||
final typing is complete.
|
final typing is complete.
|
||||||
|
|
||||||
- :ref:`template default` / :py:obj:`Result`
|
- :ref:`template default` / :py:obj:`Result`
|
||||||
- :ref:`template videos`
|
|
||||||
- :ref:`template torrent`
|
- :ref:`template torrent`
|
||||||
- :ref:`template map`
|
- :ref:`template map`
|
||||||
- :ref:`template packages`
|
- :ref:`template packages`
|
||||||
|
|||||||
@@ -129,29 +129,6 @@ audio_src : uri,
|
|||||||
URL of an embedded ``<audio controls>``.
|
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:
|
.. _template torrent:
|
||||||
|
|
||||||
``torrent.html``
|
``torrent.html``
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ __all__ = [
|
|||||||
"File",
|
"File",
|
||||||
"Image",
|
"Image",
|
||||||
"ImageRef",
|
"ImageRef",
|
||||||
|
"Video",
|
||||||
]
|
]
|
||||||
|
|
||||||
import typing as t
|
import typing as t
|
||||||
@@ -40,6 +41,7 @@ from .code import Code
|
|||||||
from .paper import Paper
|
from .paper import Paper
|
||||||
from .file import File
|
from .file import File
|
||||||
from .image import Image, ImageRef
|
from .image import Image, ImageRef
|
||||||
|
from .video import Video
|
||||||
|
|
||||||
|
|
||||||
class ResultList(list[Result | LegacyResult], abc.ABC):
|
class ResultList(list[Result | LegacyResult], abc.ABC):
|
||||||
@@ -56,6 +58,7 @@ class ResultList(list[Result | LegacyResult], abc.ABC):
|
|||||||
Paper = Paper
|
Paper = Paper
|
||||||
File = File
|
File = File
|
||||||
Image = Image
|
Image = Image
|
||||||
|
Video = Video
|
||||||
MainResult = MainResult
|
MainResult = MainResult
|
||||||
Result = Result
|
Result = Result
|
||||||
Translations = Translations
|
Translations = Translations
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ from collections.abc import Callable
|
|||||||
import msgspec
|
import msgspec
|
||||||
|
|
||||||
from searx import logger
|
from searx import logger
|
||||||
from searx.utils import get_embedded_stream_url
|
|
||||||
|
|
||||||
log = logger.getChild("result_types")
|
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."""
|
"""URL of a image that is displayed in the result item."""
|
||||||
|
|
||||||
iframe_src: str = ""
|
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 = ""
|
audio_src: str = ""
|
||||||
"""URL of an embedded ``<audio controls>``."""
|
"""URL of an embedded ``<audio controls>``."""
|
||||||
@@ -542,10 +545,6 @@ class LegacyResult(dict[str, t.Any]):
|
|||||||
DeprecationWarning,
|
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:
|
def __getattr__(self, name: str, default: t.Any = UNSET) -> t.Any:
|
||||||
if default == UNSET and name not in self:
|
if default == UNSET and name not in self:
|
||||||
raise AttributeError(f"LegacyResult object has no field named: {name}")
|
raise AttributeError(f"LegacyResult object has no field named: {name}")
|
||||||
|
|||||||
30
searx/result_types/video.py
Normal file
30
searx/result_types/video.py
Normal 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)
|
||||||
@@ -593,13 +593,24 @@ def eval_xpath_getindex(
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def get_embedded_stream_url(url: str):
|
def get_embedded_stream_url(url: str) -> str:
|
||||||
"""
|
"""Converts a standard video URL into its embed format.
|
||||||
Converts a standard video URL into its embed format. Supported services include Youtube,
|
|
||||||
Facebook, Instagram, TikTok, Dailymotion, and Bilibili.
|
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)
|
parsed_url = urlparse(url)
|
||||||
iframe_src = None
|
iframe_src = ""
|
||||||
|
|
||||||
# YouTube
|
# YouTube
|
||||||
if parsed_url.netloc in ['www.youtube.com', 'youtube.com'] and parsed_url.path == '/watch' and parsed_url.query:
|
if parsed_url.netloc in ['www.youtube.com', 'youtube.com'] and parsed_url.path == '/watch' and parsed_url.query:
|
||||||
|
|||||||
Reference in New Issue
Block a user