wttr.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # SPDX-License-Identifier: AGPL-3.0-or-later
  2. """wttr.in (weather forecast service)"""
  3. from json import loads
  4. from urllib.parse import quote
  5. from flask_babel import gettext
  6. about = {
  7. "website": "https://wttr.in",
  8. "wikidata_id": "Q107586666",
  9. "official_api_documentation": "https://github.com/chubin/wttr.in#json-output",
  10. "use_official_api": True,
  11. "require_api_key": False,
  12. "results": "JSON",
  13. }
  14. categories = ["weather"]
  15. url = "https://wttr.in/{query}?format=j1&lang={lang}"
  16. def get_weather_condition_key(lang):
  17. if lang == "en":
  18. return "weatherDesc"
  19. return "lang_" + lang.lower()
  20. def generate_day_table(day):
  21. res = ""
  22. res += f"<tr><td>{gettext('Average temp.')}</td><td>{day['avgtempC']}°C / {day['avgtempF']}°F</td></tr>"
  23. res += f"<tr><td>{gettext('Min temp.')}</td><td>{day['mintempC']}°C / {day['mintempF']}°F</td></tr>"
  24. res += f"<tr><td>{gettext('Max temp.')}</td><td>{day['maxtempC']}°C / {day['maxtempF']}°F</td></tr>"
  25. res += f"<tr><td>{gettext('UV index')}</td><td>{day['uvIndex']}</td></tr>"
  26. res += f"<tr><td>{gettext('Sunrise')}</td><td>{day['astronomy'][0]['sunrise']}</td></tr>"
  27. res += f"<tr><td>{gettext('Sunset')}</td><td>{day['astronomy'][0]['sunset']}</td></tr>"
  28. return res
  29. def generate_condition_table(condition, lang, current=False):
  30. res = ""
  31. if current:
  32. key = "temp_"
  33. else:
  34. key = "temp"
  35. res += (
  36. f"<tr><td><b>{gettext('Condition')}</b></td>"
  37. f"<td><b>{condition[get_weather_condition_key(lang)][0]['value']}</b></td></tr>"
  38. )
  39. res += (
  40. f"<tr><td><b>{gettext('Temperature')}</b></td>"
  41. f"<td><b>{condition[key+'C']}°C / {condition[key+'F']}°F</b></td></tr>"
  42. )
  43. res += (
  44. f"<tr><td>{gettext('Feels like')}</td><td>{condition['FeelsLikeC']}°C / {condition['FeelsLikeF']}°F</td></tr>"
  45. )
  46. res += (
  47. f"<tr><td>{gettext('Wind')}</td><td>{condition['winddir16Point']} — "
  48. f"{condition['windspeedKmph']} km/h / {condition['windspeedMiles']} mph</td></tr>"
  49. )
  50. res += (
  51. f"<tr><td>{gettext('Visibility')}</td><td>{condition['visibility']} km / {condition['visibilityMiles']} mi</td>"
  52. )
  53. res += f"<tr><td>{gettext('Humidity')}</td><td>{condition['humidity']}%</td></tr>"
  54. return res
  55. def request(query, params):
  56. if query.replace('/', '') in [":help", ":bash.function", ":translation"]:
  57. return None
  58. if params["language"] == "all":
  59. params["language"] = "en"
  60. else:
  61. params["language"] = params["language"].split("-")[0]
  62. params["url"] = url.format(query=quote(query), lang=params["language"])
  63. params["raise_for_httperror"] = False
  64. return params
  65. def response(resp):
  66. results = []
  67. if resp.status_code == 404:
  68. return []
  69. result = loads(resp.text)
  70. current = result["current_condition"][0]
  71. location = result['nearest_area'][0]
  72. forecast_indices = {3: gettext('Morning'), 4: gettext('Noon'), 6: gettext('Evening'), 7: gettext('Night')}
  73. title = f"{location['areaName'][0]['value']}, {location['region'][0]['value']}"
  74. infobox = f"<h3>{gettext('Current condition')}</h3><table><tbody>"
  75. infobox += generate_condition_table(current, resp.search_params['language'], True)
  76. infobox += "</tbody></table>"
  77. for day in result["weather"]:
  78. infobox += f"<h3>{day['date']}</h3>"
  79. infobox += "<table><tbody>"
  80. infobox += generate_day_table(day)
  81. infobox += "</tbody></table>"
  82. infobox += "<table><tbody>"
  83. for time in forecast_indices.items():
  84. infobox += f"<tr><td rowspan=\"7\"><b>{time[1]}</b></td></tr>"
  85. infobox += generate_condition_table(day['hourly'][time[0]], resp.search_params['language'])
  86. infobox += "</tbody></table>"
  87. results.append(
  88. {
  89. "infobox": title,
  90. "content": infobox,
  91. }
  92. )
  93. return results