Update src/libpoketube/init/pages-static.js
This commit is contained in:
parent
256112ec03
commit
56c02e58b2
@ -65,6 +65,128 @@ app.get("/143", (req, res) => {
|
||||
|
||||
return res.redirect(`/?number=${numberEasterEgg}`);
|
||||
});
|
||||
// GET /weather — SSR + hydrates the same EJS for no-JS users.
|
||||
// Query options:
|
||||
// ?q=Izmir (free text place)
|
||||
// ?lat=38.42&lon=27.14 (coordinates)
|
||||
// ?units=metric|imperial
|
||||
app.get("/weather", async (req, res) => {
|
||||
try {
|
||||
const q = (req.query.q || "").trim();
|
||||
const lat = req.query.lat ? Number(req.query.lat) : null;
|
||||
const lon = req.query.lon ? Number(req.query.lon) : null;
|
||||
const units = (req.query.units === "imperial") ? "imperial" : "metric";
|
||||
const tempUnit = units === "metric" ? "celsius" : "fahrenheit";
|
||||
const windUnit = units === "metric" ? "kmh" : "mph";
|
||||
|
||||
// Resolve coordinates
|
||||
let place = { name: null, lat: null, lon: null };
|
||||
if (lat != null && lon != null) {
|
||||
place = { name: `${lat.toFixed(3)}, ${lon.toFixed(3)}`, lat, lon };
|
||||
// reverse geocode (best effort)
|
||||
try {
|
||||
const r = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lon}`);
|
||||
if (r.ok) {
|
||||
const j = await r.json();
|
||||
place.name = (j.display_name || "").split(",").slice(0,2).join(", ") || place.name;
|
||||
}
|
||||
} catch {}
|
||||
} else if (q) {
|
||||
const r = await fetch(`https://nominatim.openstreetmap.org/search?format=json&limit=1&addressdetails=1&q=${encodeURIComponent(q)}`, { headers: { "Accept-Language": req.headers["accept-language"] || "en" }});
|
||||
const arr = r.ok ? await r.json() : [];
|
||||
if (!arr[0]) return renderTemplate(res, req, "weather.ejs", { ssr: { forceNoJS: true, name: "Not found" }});
|
||||
place = {
|
||||
name: (arr[0].display_name || "").split(",").slice(0,2).join(", "),
|
||||
lat: Number(arr[0].lat),
|
||||
lon: Number(arr[0].lon)
|
||||
};
|
||||
} else {
|
||||
// default: try to render minimal page with no data
|
||||
return renderTemplate(res, req, "weather.ejs", { ssr: { forceNoJS: true, name: "Choose a location" }});
|
||||
}
|
||||
|
||||
// Fetch Open-Meteo
|
||||
const url = new URL("https://api.open-meteo.com/v1/forecast");
|
||||
url.searchParams.set("latitude", place.lat);
|
||||
url.searchParams.set("longitude", place.lon);
|
||||
url.searchParams.set("current","temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,weather_code,wind_speed_10m,wind_direction_10m,pressure_msl");
|
||||
url.searchParams.set("hourly","temperature_2m,apparent_temperature,precipitation_probability,precipitation,weather_code,wind_speed_10m");
|
||||
url.searchParams.set("daily","weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,uv_index_max");
|
||||
url.searchParams.set("timezone","auto");
|
||||
url.searchParams.set("forecast_days","7");
|
||||
url.searchParams.set("temperature_unit", tempUnit);
|
||||
url.searchParams.set("windspeed_unit", windUnit);
|
||||
|
||||
const wr = await fetch(url.toString());
|
||||
if (!wr.ok) throw new Error("weather fetch failed");
|
||||
const data = await wr.json();
|
||||
|
||||
// Helpers to map WMO codes for SSR
|
||||
const codeText = (c)=>{
|
||||
if ([0].includes(c)) return "Clear sky";
|
||||
if ([1].includes(c)) return "Mostly clear";
|
||||
if ([2].includes(c)) return "Partly cloudy";
|
||||
if ([3].includes(c)) return "Overcast";
|
||||
if ([45,48].includes(c)) return "Fog";
|
||||
if ([51,53,55].includes(c)) return "Drizzle";
|
||||
if ([56,57].includes(c)) return "Freezing drizzle";
|
||||
if ([61,63,65].includes(c)) return "Rain";
|
||||
if ([66,67].includes(c)) return "Freezing rain";
|
||||
if ([71,73,75].includes(c)) return "Snow";
|
||||
if ([77].includes(c)) return "Snow grains";
|
||||
if ([80,81,82].includes(c)) return "Showers";
|
||||
if ([85,86].includes(c)) return "Snow showers";
|
||||
if ([95].includes(c)) return "Thunderstorm";
|
||||
if ([96,99].includes(c)) return "Storm & hail";
|
||||
return "—";
|
||||
};
|
||||
const codeIcon = (c,isDay)=>{
|
||||
if (c===0) return isDay ? "☀️" : "🌙";
|
||||
if ([1,2].includes(c)) return isDay ? "🌤️" : "☁️";
|
||||
if ([3].includes(c)) return "☁️";
|
||||
if ([45,48].includes(c)) return "🌫️";
|
||||
if ([51,53,55,80,81,82].includes(c)) return "🌦️";
|
||||
if ([61,63,65].includes(c)) return "🌧️";
|
||||
if ([66,67].includes(c)) return "🌧️❄️";
|
||||
if ([71,73,75,77,85,86].includes(c)) return "❄️";
|
||||
if ([95,96,99].includes(c)) return "⛈️";
|
||||
return "☁️";
|
||||
};
|
||||
|
||||
const cur = data.current || {};
|
||||
const daily = data.daily || { time:[] };
|
||||
// Next-hour precip probability best-effort
|
||||
let popNext = null;
|
||||
try {
|
||||
const idx = (data.hourly?.time||[]).findIndex(t => Date.parse(t) > Date.now());
|
||||
popNext = data.hourly?.precipitation_probability?.[idx>=0?idx:0] ?? null;
|
||||
} catch {}
|
||||
|
||||
// Prepare SSR payload
|
||||
const ssr = {
|
||||
forceNoJS: Boolean(req.query.nojs),
|
||||
name: place.name,
|
||||
lat: place.lat,
|
||||
lon: place.lon,
|
||||
windUnit,
|
||||
current: cur,
|
||||
daily: daily,
|
||||
icon: codeIcon(cur.weather_code, cur.is_day),
|
||||
desc: codeText(cur.weather_code),
|
||||
sunriseLocal: daily.sunrise ? new Date(daily.sunrise[0]).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'}) : "—",
|
||||
sunsetLocal: daily.sunset ? new Date(daily.sunset[0]).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'}) : "—",
|
||||
popNext,
|
||||
dailyIcons: (daily.weather_code||[]).map(c => codeIcon(c,1)),
|
||||
dailyTexts: (daily.weather_code||[]).map(c => codeText(c)),
|
||||
dailyLabels: (daily.time||[]).map(t => new Date(t).toLocaleDateString([], {weekday:'short',month:'short',day:'numeric'}))
|
||||
};
|
||||
|
||||
// Render
|
||||
return renderTemplate(res, req, "weather.ejs", { ssr });
|
||||
} catch (err) {
|
||||
return renderTemplate(res, req, "weather.ejs", { ssr:{ forceNoJS:true, name:"Error loading weather" } });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.get("/rewind", function (req, res) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user