Add services, videos, AI assistant, map/weather, gigs post, notifications settings, static legal pages, Google OAuth, payment router, real-user matching, newsletter, and content submission — all using nomadweb UI patterns. Co-authored-by: Cursor <cursoragent@cursor.com>
45 lines
1.2 KiB
Python
45 lines
1.2 KiB
Python
"""Open-Meteo weather for nomad cities."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from app.data.platform_data import WEATHER_CITIES
|
|
|
|
|
|
async def get_city_weather(slug: str) -> dict | None:
|
|
meta = WEATHER_CITIES.get(slug)
|
|
if not meta:
|
|
return None
|
|
url = (
|
|
"https://api.open-meteo.com/v1/forecast"
|
|
f"?latitude={meta['lat']}&longitude={meta['lng']}"
|
|
"¤t=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code"
|
|
"&timezone=auto"
|
|
)
|
|
try:
|
|
async with httpx.AsyncClient(timeout=8) as client:
|
|
res = await client.get(url)
|
|
res.raise_for_status()
|
|
data = res.json()
|
|
cur = data.get("current") or {}
|
|
return {
|
|
"slug": slug,
|
|
"name": meta["name"],
|
|
"temperature": cur.get("temperature_2m"),
|
|
"humidity": cur.get("relative_humidity_2m"),
|
|
"wind_speed": cur.get("wind_speed_10m"),
|
|
"weather_code": cur.get("weather_code"),
|
|
}
|
|
except (httpx.HTTPError, KeyError):
|
|
return {"slug": slug, "name": meta["name"], "temperature": None, "error": "unavailable"}
|
|
|
|
|
|
async def list_weather() -> list[dict]:
|
|
results = []
|
|
for slug in WEATHER_CITIES:
|
|
w = await get_city_weather(slug)
|
|
if w:
|
|
results.append(w)
|
|
return results
|