.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
duckduckgo_weather.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2"""
3DuckDuckGo Weather
4~~~~~~~~~~~~~~~~~~
5"""
6
7from typing import TYPE_CHECKING
8from json import loads
9from urllib.parse import quote
10
11from dateutil import parser as date_parser
12from flask_babel import gettext
13
14from searx.engines.duckduckgo import fetch_traits # pylint: disable=unused-import
15from searx.engines.duckduckgo import get_ddg_lang
16from searx.enginelib.traits import EngineTraits
17
18if TYPE_CHECKING:
19 import logging
20
21 logger: logging.Logger
22
23traits: EngineTraits
24
25
26about = {
27 "website": 'https://duckduckgo.com/',
28 "wikidata_id": 'Q12805',
29 "official_api_documentation": None,
30 "use_official_api": True,
31 "require_api_key": False,
32 "results": "JSON",
33}
34
35send_accept_language_header = True
36
37# engine dependent config
38categories = ["weather"]
39URL = "https://duckduckgo.com/js/spice/forecast/{query}/{lang}"
40
41
43 res = ""
44
45 res += f"<tr><td><b>{gettext('Condition')}</b></td>" f"<td><b>{condition['conditionCode']}</b></td></tr>"
46
47 res += (
48 f"<tr><td><b>{gettext('Temperature')}</b></td>"
49 f"<td><b>{condition['temperature']}°C / {c_to_f(condition['temperature'])}°F</b></td></tr>"
50 )
51
52 res += (
53 f"<tr><td>{gettext('Feels like')}</td><td>{condition['temperatureApparent']}°C / "
54 f"{c_to_f(condition['temperatureApparent'])}°F</td></tr>"
55 )
56
57 res += (
58 f"<tr><td>{gettext('Wind')}</td><td>{condition['windDirection']}° — "
59 f"{(condition['windSpeed'] * 1.6093440006147):.2f} km/h / {condition['windSpeed']} mph</td></tr>"
60 )
61
62 res += f"<tr><td>{gettext('Visibility')}</td><td>{condition['visibility']} m</td>"
63
64 res += f"<tr><td>{gettext('Humidity')}</td><td>{(condition['humidity'] * 100):.1f}%</td></tr>"
65
66 return res
67
68
70 res = ""
71
72 res += (
73 f"<tr><td>{gettext('Min temp.')}</td><td>{day['temperatureMin']}°C / "
74 f"{c_to_f(day['temperatureMin'])}°F</td></tr>"
75 )
76 res += (
77 f"<tr><td>{gettext('Max temp.')}</td><td>{day['temperatureMax']}°C / "
78 f"{c_to_f(day['temperatureMax'])}°F</td></tr>"
79 )
80 res += f"<tr><td>{gettext('UV index')}</td><td>{day['maxUvIndex']}</td></tr>"
81 res += f"<tr><td>{gettext('Sunrise')}</td><td>{date_parser.parse(day['sunrise']).strftime('%H:%M')}</td></tr>"
82 res += f"<tr><td>{gettext('Sunset')}</td><td>{date_parser.parse(day['sunset']).strftime('%H:%M')}</td></tr>"
83
84 return res
85
86
87def request(query, params):
88
89 eng_region = traits.get_region(params['searxng_locale'], traits.all_locale)
90 eng_lang = get_ddg_lang(traits, params['searxng_locale'])
91
92 # !ddw paris :es-AR --> {'ad': 'es_AR', 'ah': 'ar-es', 'l': 'ar-es'}
93 params['cookies']['ad'] = eng_lang
94 params['cookies']['ah'] = eng_region
95 params['cookies']['l'] = eng_region
96 logger.debug("cookies: %s", params['cookies'])
97
98 params["url"] = URL.format(query=quote(query), lang=eng_lang.split('_')[0])
99 return params
100
101
102def c_to_f(temperature):
103 return "%.2f" % ((temperature * 1.8) + 32)
104
105
106def response(resp):
107 results = []
108
109 if resp.text.strip() == "ddg_spice_forecast();":
110 return []
111
112 result = loads(resp.text[resp.text.find('\n') + 1 : resp.text.rfind('\n') - 2])
113
114 current = result["currentWeather"]
115
116 title = result['location']
117
118 infobox = f"<h3>{gettext('Current condition')}</h3><table><tbody>"
119
120 infobox += generate_condition_table(current)
121
122 infobox += "</tbody></table>"
123
124 last_date = None
125
126 for time in result['forecastHourly']['hours']:
127 current_time = date_parser.parse(time['forecastStart'])
128
129 if last_date != current_time.date():
130 if last_date is not None:
131 infobox += "</tbody></table>"
132
133 infobox += f"<h3>{current_time.strftime('%Y-%m-%d')}</h3>"
134
135 infobox += "<table><tbody>"
136
137 for day in result['forecastDaily']['days']:
138 if date_parser.parse(day['forecastStart']).date() == current_time.date():
139 infobox += generate_day_table(day)
140
141 infobox += "</tbody></table><table><tbody>"
142
143 last_date = current_time.date()
144
145 infobox += f"<tr><td rowspan=\"7\"><b>{current_time.strftime('%H:%M')}</b></td></tr>"
146
147 infobox += generate_condition_table(time)
148
149 infobox += "</tbody></table>"
150
151 results.append(
152 {
153 "infobox": title,
154 "content": infobox,
155 }
156 )
157
158 return results