Compare commits
No commits in common. "c9ef692c9a2f517e314c14688b88f078f56da2af" and "1499e46a0fdd84ab4fdaeae8c5b4dacbc6c8dd2c" have entirely different histories.
c9ef692c9a
...
1499e46a0f
3 changed files with 2 additions and 177 deletions
|
|
@ -1,175 +0,0 @@
|
||||||
import crypto from "node:crypto";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User agent header.
|
|
||||||
*/
|
|
||||||
const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token secret. Used to hash the token.
|
|
||||||
*/
|
|
||||||
const WEATHER_TOKEN_SECRET = "gravisfrontem";
|
|
||||||
|
|
||||||
interface YandexWeatherData {
|
|
||||||
/**
|
|
||||||
* Message from the server.
|
|
||||||
*/
|
|
||||||
message?: string | null;
|
|
||||||
|
|
||||||
info: {
|
|
||||||
/**
|
|
||||||
* URL of the location page on Yandex Weather
|
|
||||||
**/
|
|
||||||
url: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
fact: {
|
|
||||||
/**
|
|
||||||
* Current air temperature in °C
|
|
||||||
**/
|
|
||||||
temp: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Water temperature in °C (may be missing)
|
|
||||||
**/
|
|
||||||
temp_water?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perceived (“feels like”) temperature in °C
|
|
||||||
**/
|
|
||||||
feels_like: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Weather condition code (e.g., "clear", "rain")
|
|
||||||
**/
|
|
||||||
condition: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wind speed in m/s
|
|
||||||
**/
|
|
||||||
wind_speed: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wind gust speed in m/s (may be missing)
|
|
||||||
**/
|
|
||||||
wind_gust?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wind direction code (e.g., "nw", "s")
|
|
||||||
**/
|
|
||||||
wind_dir: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Atmospheric pressure in mmHg
|
|
||||||
**/
|
|
||||||
pressure_mm: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Air humidity percentage
|
|
||||||
**/
|
|
||||||
humidity: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FetchWeatherResult {
|
|
||||||
/**
|
|
||||||
* Link to the weather in location.
|
|
||||||
**/
|
|
||||||
url: string;
|
|
||||||
|
|
||||||
temperature: {
|
|
||||||
/**
|
|
||||||
* Current temperature in °C.
|
|
||||||
**/
|
|
||||||
current: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Water temperature in °C.
|
|
||||||
**/
|
|
||||||
water?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perceived ("feels like") temperature in °C.
|
|
||||||
**/
|
|
||||||
feelsLike: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Weather condition.
|
|
||||||
**/
|
|
||||||
condition: string;
|
|
||||||
|
|
||||||
wind: {
|
|
||||||
/**
|
|
||||||
* Wind speed in m/s.
|
|
||||||
**/
|
|
||||||
speed: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wind gust speed in m/s.
|
|
||||||
**/
|
|
||||||
gust?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wind direction code.
|
|
||||||
**/
|
|
||||||
direction: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Atmospheric pressure in mmHg.
|
|
||||||
**/
|
|
||||||
pressure: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Air humidity percentage.
|
|
||||||
**/
|
|
||||||
humidity: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWeatherHeaders() {
|
|
||||||
const timestamp = Date.now();
|
|
||||||
|
|
||||||
return {
|
|
||||||
// NOTE: no one would pay ~$7k to have a weather on their personal website
|
|
||||||
'x-yandex-weather-timestamp': timestamp.toString(),
|
|
||||||
'x-yandex-weather-token':
|
|
||||||
crypto.createHash('md5').update(`${WEATHER_TOKEN_SECRET}${timestamp}`).digest('hex'),
|
|
||||||
'x-yandex-weather-client': 'YandexWeatherFront2',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function fetchWeather(lat: number, lon: number): Promise<FetchWeatherResult> {
|
|
||||||
const response = await fetch(
|
|
||||||
`https://api.weather.yandex.ru/v2/informers?lat=${lat}&lon=${lon}&lang=en_US`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'user-agent': USER_AGENT,
|
|
||||||
...getWeatherHeaders(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const result: YandexWeatherData = await response.json();
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`Yandex Weather API error: ${result.message}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: result.info.url,
|
|
||||||
temperature: {
|
|
||||||
current: result.fact.temp,
|
|
||||||
water: result.fact.temp_water,
|
|
||||||
feelsLike: result.fact.feels_like,
|
|
||||||
},
|
|
||||||
condition: result.fact.condition,
|
|
||||||
wind: {
|
|
||||||
speed: result.fact.wind_speed,
|
|
||||||
gust: result.fact.wind_gust,
|
|
||||||
direction: result.fact.wind_dir,
|
|
||||||
},
|
|
||||||
pressure: result.fact.pressure_mm,
|
|
||||||
humidity: result.fact.humidity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -105,7 +105,7 @@ Metro-like tile. Must be in a group to display correctly.
|
||||||
/**
|
/**
|
||||||
* Pages.
|
* Pages.
|
||||||
*/
|
*/
|
||||||
children: () => any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
children: () => any;
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ A group of tiles. Places them correctly in a grid.
|
||||||
/**
|
/**
|
||||||
* Tiles.
|
* Tiles.
|
||||||
*/
|
*/
|
||||||
children: () => any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
children: () => any;
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
// NOTE: to make it usable for small tiles
|
// NOTE: to make it usable for small tiles
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue