From 8aa018db95d3597ca7bf861fd3abd09f8f114349 Mon Sep 17 00:00:00 2001 From: ta Date: Sat, 6 Aug 2022 20:13:42 +0700 Subject: [PATCH 1/4] add wttr.in engine --- searx/engines/wttr.py | 134 ++++++++++++++++++++++++++++++++++++++++++ searx/settings.yml | 5 ++ 2 files changed, 139 insertions(+) create mode 100644 searx/engines/wttr.py diff --git a/searx/engines/wttr.py b/searx/engines/wttr.py new file mode 100644 index 000000000..fd80c6db7 --- /dev/null +++ b/searx/engines/wttr.py @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +# lint: pylint +"""wttr.in""" + +from json import loads +from urllib.parse import quote +from flask_babel import gettext + +about = { + "website": "https://wttr.in", + "wikidata_id": None, + "official_api_documentation": "https://github.com/chubin/wttr.in#json-output", + "use_official_api": True, + "require_api_key": False, + "results": "JSON", +} + +categories = ["others"] + +url = "https://wttr.in/{query}?format=j1&lang={lang}" + + +def get_weather_condition_key(lang): + if lang == "en": + return "weatherDesc" + + return "lang_" + lang.lower() + + +def generate_day_table(day): + res = "" + + res += f"{gettext('Average temp.')}{day['avgtempC']}°C / {day['avgtempF']}°F" + res += f"{gettext('Min temp.')}{day['mintempC']}°C / {day['mintempF']}°F" + res += f"{gettext('Max temp.')}{day['maxtempC']}°C / {day['maxtempF']}°F" + res += f"{gettext('UV index')}{day['uvIndex']}" + res += f"{gettext('Sunrise')}{day['astronomy'][0]['sunrise']}" + res += f"{gettext('Sunset')}{day['astronomy'][0]['sunset']}" + + return res + + +def generate_condition_table(condition, lang, current=False): + res = "" + + if current: + key = "temp_" + else: + key = "temp" + + res += ( + f"{gettext('Condition')}" + f"{condition[get_weather_condition_key(lang)][0]['value']}" + ) + res += ( + f"{gettext('Temperature')}" + f"{condition[key+'C']}°C / {condition[key+'F']}°F" + ) + res += ( + f"{gettext('Feels like')}{condition['FeelsLikeC']}°C / {condition['FeelsLikeF']}°F" + ) + res += ( + f"{gettext('Wind')}{condition['winddir16Point']} — " + f"{condition['windspeedKmph']} km/h / {condition['windspeedMiles']} mph" + ) + res += ( + f"{gettext('Visibility')}{condition['visibility']} km / {condition['visibilityMiles']} mi" + ) + res += f"{gettext('Humidity')}{condition['humidity']}%" + + return res + + +def request(query, params): + if query.replace('/', '') in [":help", ":bash.function", ":translation"]: + return None + + if params["language"] == "all": + params["language"] = "en" + else: + params["language"] = params["language"].split("-")[0] + + params["url"] = url.format(query=quote(query), lang=params["language"]) + + return params + + +def response(resp): + results = [] + + result = loads(resp.text) + + current = result["current_condition"][0] + location = result['nearest_area'][0] + + forecast_indices = {3: gettext('Morning'), 4: gettext('Noon'), 6: gettext('Evening'), 7: gettext('Night')} + + title = f"{location['areaName'][0]['value']}, {location['region'][0]['value']}" + + infobox = f"

{gettext('Current condition')}

" + + infobox += generate_condition_table(current, resp.search_params['language'], True) + + infobox += "
" + + for day in result["weather"]: + infobox += "
" + infobox += f"

{day['date']}

" + + infobox += f"

{gettext('Overview')}

" + infobox += "" + + infobox += generate_day_table(day) + + infobox += "
" + + infobox += f"

{gettext('Forecast')}

" + infobox += "" + + for time in forecast_indices.items(): + infobox += f"" + + infobox += generate_condition_table(day['hourly'][time[0]], resp.search_params['language']) + + infobox += "
{time[1]}
" + + results.append( + { + "infobox": title, + "content": infobox, + } + ) + + return results diff --git a/searx/settings.yml b/searx/settings.yml index 3694c177a..6c7b4ea69 100644 --- a/searx/settings.yml +++ b/searx/settings.yml @@ -1760,6 +1760,11 @@ engines: results: HTML language: fr + - name: wttr.in + engine: wttr + shortcut: wttr + timeout: 9.0 + - name: brave shortcut: brave engine: xpath From 8c318562e236613bdef3c4e058a2223f139cb9bb Mon Sep 17 00:00:00 2001 From: liimee <70614549+liimee@users.noreply.github.com> Date: Sun, 7 Aug 2022 14:57:10 +0700 Subject: [PATCH 2/4] add description and wikidata ID to wttr.in engine --- searx/engines/wttr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/searx/engines/wttr.py b/searx/engines/wttr.py index fd80c6db7..3c7b0927d 100644 --- a/searx/engines/wttr.py +++ b/searx/engines/wttr.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-or-later # lint: pylint -"""wttr.in""" +"""wttr.in (weather forecast service)""" from json import loads from urllib.parse import quote @@ -8,7 +8,7 @@ from flask_babel import gettext about = { "website": "https://wttr.in", - "wikidata_id": None, + "wikidata_id": "Q107586666", "official_api_documentation": "https://github.com/chubin/wttr.in#json-output", "use_official_api": True, "require_api_key": False, From e64cca8c3f5833cb88556d0ceabd0d17cac313e0 Mon Sep 17 00:00:00 2001 From: ta Date: Mon, 22 Aug 2022 17:04:29 +0700 Subject: [PATCH 3/4] don't raise error when nothing was found --- searx/engines/wttr.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/searx/engines/wttr.py b/searx/engines/wttr.py index 3c7b0927d..60e91114f 100644 --- a/searx/engines/wttr.py +++ b/searx/engines/wttr.py @@ -82,12 +82,17 @@ def request(query, params): params["url"] = url.format(query=quote(query), lang=params["language"]) + params["raise_for_httperror"] = False + return params def response(resp): results = [] + if resp.status_code == 404: + return [] + result = loads(resp.text) current = result["current_condition"][0] From 85b5293e4085543e145a74a95c28bb1f2fb68876 Mon Sep 17 00:00:00 2001 From: ta Date: Wed, 31 Aug 2022 18:29:50 +0700 Subject: [PATCH 4/4] simplify infobox result --- searx/engines/wttr.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/searx/engines/wttr.py b/searx/engines/wttr.py index 60e91114f..d3da2748a 100644 --- a/searx/engines/wttr.py +++ b/searx/engines/wttr.py @@ -102,24 +102,21 @@ def response(resp): title = f"{location['areaName'][0]['value']}, {location['region'][0]['value']}" - infobox = f"

{gettext('Current condition')}

" + infobox = f"

{gettext('Current condition')}

" infobox += generate_condition_table(current, resp.search_params['language'], True) infobox += "
" for day in result["weather"]: - infobox += "
" - infobox += f"

{day['date']}

" + infobox += f"

{day['date']}

" - infobox += f"

{gettext('Overview')}

" infobox += "" infobox += generate_day_table(day) infobox += "
" - infobox += f"

{gettext('Forecast')}

" infobox += "" for time in forecast_indices.items():