Fix: weather uses open-meteo directly (wttr.in hangs)
This commit is contained in:
@@ -1,67 +1,36 @@
|
|||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
export async function GET() {
|
const WMO_DESCRIPTIONS: Record<number, string> = {
|
||||||
try {
|
0: "Ясно", 1: "Преимущественно ясно", 2: "Переменная облачность", 3: "Пасмурно",
|
||||||
// Попробовать несколько источников
|
45: "Туман", 48: "Ледяной туман", 51: "Лёгкая морось", 53: "Морось", 55: "Сильная морось",
|
||||||
const sources = [
|
61: "Лёгкий дождь", 63: "Дождь", 65: "Сильный дождь",
|
||||||
"https://wttr.in/Saint+Petersburg?format=j1",
|
71: "Лёгкий снег", 73: "Снег", 75: "Сильный снег",
|
||||||
"https://wttr.in/Saint%20Petersburg?format=j1",
|
80: "Небольшой ливень", 81: "Ливень", 82: "Сильный ливень", 95: "Гроза",
|
||||||
"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");
|
|
||||||
|
|
||||||
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) }
|
|
||||||
);
|
|
||||||
const meteoData = await meteoRes.json();
|
|
||||||
|
|
||||||
// Нормализовать в формат wttr.in
|
|
||||||
const wmoDescriptions: Record<number, string> = {
|
|
||||||
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",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
// Open-Meteo: координаты Санкт-Петербурга
|
||||||
|
const lat = 59.9343;
|
||||||
|
const lon = 30.3351;
|
||||||
|
|
||||||
|
const meteoRes = await fetch(
|
||||||
|
`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();
|
||||||
const c = meteoData.current;
|
const c = meteoData.current;
|
||||||
|
|
||||||
const normalized = {
|
const normalized = {
|
||||||
current_condition: [{
|
current_condition: [{
|
||||||
temp_C: Math.round(c.temperature_2m).toString(),
|
temp_C: Math.round(c.temperature_2m).toString(),
|
||||||
FeelsLikeC: Math.round(c.apparent_temperature).toString(),
|
FeelsLikeC: Math.round(c.apparent_temperature).toString(),
|
||||||
humidity: Math.round(c.relative_humidity_2m).toString(),
|
humidity: Math.round(c.relative_humidity_2m).toString(),
|
||||||
windspeedKmph: Math.round(c.wind_speed_10m).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",
|
source: "open-meteo",
|
||||||
};
|
};
|
||||||
|
|||||||
31
weather-proxy.py
Normal file
31
weather-proxy.py
Normal file
@@ -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()
|
||||||
Reference in New Issue
Block a user