From 5ca08c18134123fd5f9a457829090410221a93ce Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 26 Apr 2025 22:21:39 +0200 Subject: [PATCH] [feat] plugins: add new time/timezone search plugin The plugin uses the ``GeoLocation`` class, which is already implemented in the context of weather forecasts, to determine the time zone. The ``DateTime`` class is used for the localized display of date and time. Co-authored-by: Markus Heiser --- docs/dev/plugins/builtins.rst | 1 + docs/dev/plugins/time_zone.rst | 8 ++++ searx/plugins/time_zone.py | 70 ++++++++++++++++++++++++++++++++++ searx/settings.yml | 3 ++ searx/weather.py | 5 +++ 5 files changed, 87 insertions(+) create mode 100644 docs/dev/plugins/time_zone.rst create mode 100644 searx/plugins/time_zone.py diff --git a/docs/dev/plugins/builtins.rst b/docs/dev/plugins/builtins.rst index 902092e11..f0473dd49 100644 --- a/docs/dev/plugins/builtins.rst +++ b/docs/dev/plugins/builtins.rst @@ -13,3 +13,4 @@ Built-in Plugins self_info tor_check unit_converter + time_zone diff --git a/docs/dev/plugins/time_zone.rst b/docs/dev/plugins/time_zone.rst new file mode 100644 index 000000000..dd17924d6 --- /dev/null +++ b/docs/dev/plugins/time_zone.rst @@ -0,0 +1,8 @@ +.. _time zone plugin: + +========= +Time Zone +========= + +.. automodule:: searx.plugins.time_zone + :members: diff --git a/searx/plugins/time_zone.py b/searx/plugins/time_zone.py new file mode 100644 index 000000000..f54a9ce6c --- /dev/null +++ b/searx/plugins/time_zone.py @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +# pylint: disable=missing-module-docstring + +from __future__ import annotations +import typing as t + +import datetime + +from flask_babel import gettext # type: ignore +from searx.result_types import EngineResults +from searx.weather import DateTime, GeoLocation + +from . import Plugin, PluginInfo + +if t.TYPE_CHECKING: + from searx.search import SearchWithPlugins + from searx.extended_types import SXNG_Request + from searx.plugins import PluginCfg + + +@t.final +class SXNGPlugin(Plugin): + """Plugin to display the current time at different timezones (usually the + query city).""" + + id: str = "time_zone" + keywords: list[str] = ["time", "timezone", "now", "clock", "timezones"] + + def __init__(self, plg_cfg: "PluginCfg"): + super().__init__(plg_cfg) + + self.info = PluginInfo( + id=self.id, + name=gettext("Timezones plugin"), + description=gettext("Display the current time on different time zones."), + preference_section="query", + examples=["time Berlin", "clock Los Angeles"], + ) + + def post_search(self, request: "SXNG_Request", search: "SearchWithPlugins") -> EngineResults: + """The plugin uses the :py:obj:`searx.weather.GeoLocation` class, which + is already implemented in the context of weather forecasts, to determine + the time zone. The :py:obj:`searx.weather.DateTime` class is used for + the localized display of date and time.""" + + results = EngineResults() + if search.search_query.pageno > 1: + return results + + # remove keywords from the query + query = search.search_query.query + query_parts = filter(lambda part: part.lower() not in self.keywords, query.split(" ")) + search_term = " ".join(query_parts).strip() + + if not search_term: + date_time = DateTime(time=datetime.datetime.now()) + results.add(results.types.Answer(answer=date_time.l10n())) + return results + + geo = GeoLocation.by_query(search_term=search_term) + if geo: + date_time = DateTime(time=datetime.datetime.now(tz=geo.zoneinfo)) + tz_name = geo.timezone.replace('_', ' ') + results.add( + results.types.Answer( + answer=(f"{tz_name}:" f" {date_time.l10n()} ({date_time.datetime.strftime('%Z')})") + ) + ) + + return results diff --git a/searx/settings.yml b/searx/settings.yml index 7d95e3d16..c940c7f11 100644 --- a/searx/settings.yml +++ b/searx/settings.yml @@ -238,6 +238,9 @@ plugins: searx.plugins.hostnames.SXNGPlugin: active: true + searx.plugins.time_zone.SXNGPlugin: + active: true + searx.plugins.oa_doi_rewrite.SXNGPlugin: active: false diff --git a/searx/weather.py b/searx/weather.py index 793dc09c4..cb10181a0 100644 --- a/searx/weather.py +++ b/searx/weather.py @@ -20,6 +20,7 @@ import typing import base64 import datetime import dataclasses +import zoneinfo from urllib.parse import quote_plus @@ -137,6 +138,10 @@ class GeoLocation: country_code: str # 2-Character ISO-3166-1 alpha2 country code. E.g. DE for Germany timezone: str # Time zone using time zone database definitions + @property + def zoneinfo(self) -> zoneinfo.ZoneInfo: + return zoneinfo.ZoneInfo(self.timezone) + def __str__(self): return self.name