From 692059984e206b8a021ba9e2833b74782a166dbf Mon Sep 17 00:00:00 2001 From: Sohrab Behdani Date: Sun, 7 Jul 2024 14:43:55 +0330 Subject: [PATCH 1/2] weather plugin for moa --- searx/plugins/weather.py | 192 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 searx/plugins/weather.py diff --git a/searx/plugins/weather.py b/searx/plugins/weather.py new file mode 100644 index 00000000000..2094adfafd4 --- /dev/null +++ b/searx/plugins/weather.py @@ -0,0 +1,192 @@ +from flask_babel import gettext +import requests +import re + +name = "MOA Weather Data Plugin" +description = gettext("Displays weather data for a given location using the Open Meteo API, with improved formatting.") +default_on = True +preference_section = 'general' + +query_re = re.compile(r'weather\s+(?:in\s+)?(.+)', re.IGNORECASE) + +conditions = { + 99: { + "name": gettext("Thunderstorm with heavy hail"), + "emoji": "⛈ī¸" + }, + 96: { + "name": gettext("Thunderstorm with slight hail"), + "emoji": "⛈ī¸" + }, + 95: { + "name": gettext("Thunderstorm"), + "emoji": "🌩ī¸" + }, + 86: { + "name": gettext("Heavy snow showers"), + "emoji": "🌧ī¸" + }, + 85: { + "name": gettext("Slight snow showers"), + "emoji": "🌧ī¸" + }, + 82: { + "name": gettext("Violent rain showers"), + "emoji": "🌧ī¸" + }, + 81: { + "name": gettext("Moderate rain showers"), + "emoji": "🌧ī¸" + }, + 80: { + "name": gettext("Slight rain showers"), + "emoji": "🌧ī¸" + }, + 77: { + "name": gettext("Snow grains"), + "emoji": "🌨ī¸" + }, + 75: { + "name": gettext("Heavy snowfall"), + "emoji": "🌨ī¸" + }, + 73: { + "name": gettext("Moderate snowfall"), + "emoji": "🌨ī¸" + }, + 71: { + "name": gettext("Slight snowfall"), + "emoji": "🌨ī¸" + }, + 67: { + "name": gettext("Heavy freezing rain"), + "emoji": "🌧ī¸" + }, + 66: { + "name": gettext("Light freezing rain"), + "emoji": "🌧ī¸" + }, + 65: { + "name": gettext("Heavy rain"), + "emoji": "🌧ī¸" + }, + 63: { + "name": gettext("Moderate rain"), + "emoji": "🌧ī¸" + }, + 61: { + "name": gettext("Slight rain"), + "emoji": "🌧ī¸" + }, + 57: { + "name": gettext("Dense freezing drizzle"), + "emoji": "🌧ī¸" + }, + 56: { + "name": gettext("Light freezing drizzle"), + "emoji": "🌧ī¸" + }, + 55: { + "name": gettext("Dense drizzle"), + "emoji": "🌧ī¸" + }, + 53: { + "name": gettext("Moderate drizzle"), + "emoji": "🌧ī¸" + }, + 51: { + "name": gettext("Light drizzle"), + "emoji": "🌧ī¸" + }, + 48: { + "name": gettext("Depositing rime fog"), + "emoji": "đŸŒĢī¸" + }, + 45: { + "name": gettext("Fog"), + "emoji": "đŸŒĢī¸" + }, + 3: { + "name": gettext("Overcast"), + "emoji": "☁ī¸" + }, + 2: { + "name": gettext("Partly cloudy"), + "emoji": "đŸŒĨī¸" + }, + 1: { + "name": gettext("Mainly clear"), + "emoji": "🌤ī¸" + }, + 0: { + "name": gettext("Clear"), + "emoji": "☀ī¸", + "emoji_night": "🌙" + } +} + +def query_location(location_query): + geocoding_url = f'https://nominatim.openstreetmap.org/search?format=json&q={location_query}' + response = requests.get(geocoding_url).json() + if response: + lat = response[0]['lat'] + lon = response[0]['lon'] + return { + 'lat': lat, + 'lon': lon, + 'display_coords': gettext('%s °N, %s °E') % (lat, lon), + 'display_name': response[0]['display_name'] + } + + return None + +def fetch_weather_data(lat, lon, params): + weather_url = f'https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}' + if params: + weather_url += f'&{params}' + response = requests.get(weather_url).json() + return response + +def get_named_weather_condition(current_weather, with_emoji=False): + for code, condition in conditions.items(): + if current_weather['weather_code'] >= code: + condition = conditions[code] + emoji = condition['emoji'] if current_weather.get('is_day', True) else condition.get('emoji_night', condition['emoji']) + return f"{emoji} {condition['name']}" if with_emoji else condition['name'] + return gettext('Unknown') + +def post_search(request, search): + match = query_re.match(search.search_query.query) + if not match: + return True # Continue with normal search if no match + + location_query = match.group(1) + location = query_location(location_query) + + if not location: + search.result_container.answers.clear() + search.result_container.answers['weather_error'] = {'answer': gettext('Location not found or invalid coordinates format.')} + return True + + weather_data = fetch_weather_data(location['lat'], location['lon'], 'current=weather_code,is_day,temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m') + if 'current' in weather_data: + current_weather = weather_data['current'] + else: + search.result_container.answers.clear() + search.result_container.answers['weather_error'] = {'answer': gettext('Weather data not available.')} + return True + + search.result_container.answers.clear() + search.result_container.answers['weather'] = { + 'title': gettext('Weather for %s') % f"{location['display_name']} ({location['display_coords']})", + 'fields': [ + {'label': gettext('Condition'), 'value': get_named_weather_condition(current_weather, with_emoji=True)}, + {'label': gettext('Temperature'), 'value': f"{current_weather['temperature_2m']}°C"}, + {'label': gettext('Wind Speed'), 'value': f"{current_weather['wind_speed_10m']}m/s"} + ], + 'sources': [ + {'title': 'Open Meteo', 'url': 'https://open-meteo.com/'}, + {'title': 'OpenStreetMap', 'url': 'https://www.openstreetmap.org/'} + ], + } + return True From 47d57f5adbd229771e848bae6b71f00d384431dd Mon Sep 17 00:00:00 2001 From: Jafar Farganlooj <86001599+mehr32@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:19:49 +0330 Subject: [PATCH 2/2] Update weather.py --- searx/plugins/weather.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/searx/plugins/weather.py b/searx/plugins/weather.py index 2094adfafd4..1a892a048a2 100644 --- a/searx/plugins/weather.py +++ b/searx/plugins/weather.py @@ -4,7 +4,7 @@ name = "MOA Weather Data Plugin" description = gettext("Displays weather data for a given location using the Open Meteo API, with improved formatting.") -default_on = True +default_on = False preference_section = 'general' query_re = re.compile(r'weather\s+(?:in\s+)?(.+)', re.IGNORECASE)