From 0039132aec059068c1546d5a0885cdfddc5decd9 Mon Sep 17 00:00:00 2001 From: Cosmo Date: Wed, 15 Apr 2026 21:47:48 +0000 Subject: [PATCH] Fix: weather uses open-meteo directly (wttr.in hangs) --- src/app/api/weather/route.ts | 69 ++++++++++-------------------------- weather-proxy.py | 31 ++++++++++++++++ 2 files changed, 50 insertions(+), 50 deletions(-) create mode 100644 weather-proxy.py diff --git a/src/app/api/weather/route.ts b/src/app/api/weather/route.ts index f69bcd5..03e9d04 100644 --- a/src/app/api/weather/route.ts +++ b/src/app/api/weather/route.ts @@ -1,71 +1,40 @@ export const dynamic = "force-dynamic"; import { NextResponse } from "next/server"; +const WMO_DESCRIPTIONS: Record = { + 0: "Ясно", 1: "Преимущественно ясно", 2: "Переменная облачность", 3: "Пасмурно", + 45: "Туман", 48: "Ледяной туман", 51: "Лёгкая морось", 53: "Морось", 55: "Сильная морось", + 61: "Лёгкий дождь", 63: "Дождь", 65: "Сильный дождь", + 71: "Лёгкий снег", 73: "Снег", 75: "Сильный снег", + 80: "Небольшой ливень", 81: "Ливень", 82: "Сильный ливень", 95: "Гроза", +}; + export async function GET() { try { - // Попробовать несколько источников - const sources = [ - "https://wttr.in/Saint+Petersburg?format=j1", - "https://wttr.in/Saint%20Petersburg?format=j1", - "http://wttr.in/Saint+Petersburg?format=j1", - ]; - - let lastError: Error | null = null; - - for (const url of sources) { - try { - const res = await fetch(url, { - headers: { - "User-Agent": "curl/7.74.0", - "Accept": "application/json", - }, - signal: AbortSignal.timeout(5000), - }); - if (res.ok) { - const data = await res.json(); - return NextResponse.json(data); - } - } catch (e) { - lastError = e as Error; - continue; - } - } - - // Fallback: open-meteo (не через Cloudflare) - const geoRes = await fetch("https://geocoding-api.open-meteo.com/v1/search?name=Saint+Petersburg&country=Russia&count=1", { - signal: AbortSignal.timeout(5000), - }); - const geoData = await geoRes.json(); - const loc = geoData.results?.[0]; - - if (!loc) throw new Error("Geocoding failed"); - + // Open-Meteo: координаты Санкт-Петербурга + const lat = 59.9343; + const lon = 30.3351; + const meteoRes = await fetch( - `https://api.open-meteo.com/v1/forecast?latitude=${loc.latitude}&longitude=${loc.longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,weather_code&wind_speed_unit=kmh`, - { signal: AbortSignal.timeout(5000) } + `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,weather_code&wind_speed_unit=kmh`, + { signal: AbortSignal.timeout(6000) } ); + + if (!meteoRes.ok) throw new Error("Open-Meteo error"); const meteoData = await meteoRes.json(); - - // Нормализовать в формат wttr.in - const wmoDescriptions: Record = { - 0: "Clear sky", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", - 45: "Foggy", 48: "Icy fog", 51: "Light drizzle", 53: "Drizzle", 55: "Heavy drizzle", - 61: "Light rain", 63: "Rain", 65: "Heavy rain", 71: "Light snow", 73: "Snow", 75: "Heavy snow", - 80: "Light showers", 81: "Showers", 82: "Heavy showers", 95: "Thunderstorm", - }; - const c = meteoData.current; + const normalized = { current_condition: [{ temp_C: Math.round(c.temperature_2m).toString(), FeelsLikeC: Math.round(c.apparent_temperature).toString(), humidity: Math.round(c.relative_humidity_2m).toString(), windspeedKmph: Math.round(c.wind_speed_10m).toString(), - weatherDesc: [{ value: wmoDescriptions[c.weather_code] || "Unknown" }], + weatherDesc: [{ value: WMO_DESCRIPTIONS[c.weather_code] ?? "Неизвестно" }], }], source: "open-meteo", }; - + return NextResponse.json(normalized); } catch (e) { return NextResponse.json({ error: "Failed to fetch weather" }, { status: 500 }); diff --git a/weather-proxy.py b/weather-proxy.py new file mode 100644 index 0000000..0e7e644 --- /dev/null +++ b/weather-proxy.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +from http.server import HTTPServer, BaseHTTPRequestHandler +import subprocess, json + +class Handler(BaseHTTPRequestHandler): + def log_message(self, *a): pass + def do_GET(self): + try: + cmd = ["curl", "-s", "--max-time", "5", "https://wttr.in/Saint+Petersburg?format=j1"] + result = subprocess.run(cmd, timeout=8, capture_output=True, text=True) + if result.stdout and len(result.stdout) > 10: + body = result.stdout.encode() + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", len(body)) + self.end_headers() + self.wfile.write(body) + else: + raise Exception("No data rc=" + str(result.returncode)) + except Exception as e: + err = json.dumps({"error": str(e)}).encode() + self.send_response(502) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", len(err)) + self.end_headers() + self.wfile.write(err) + +if __name__ == "__main__": + server = HTTPServer(("0.0.0.0", 8765), Handler) + print("Weather proxy on :8765", flush=True) + server.serve_forever()