Compare commits

..

No commits in common. "c9ef692c9a2f517e314c14688b88f078f56da2af" and "1499e46a0fdd84ab4fdaeae8c5b4dacbc6c8dd2c" have entirely different histories.

3 changed files with 2 additions and 177 deletions

View file

@ -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,
};
}

View file

@ -105,7 +105,7 @@ Metro-like tile. Must be in a group to display correctly.
/**
* Pages.
*/
children: () => any; // eslint-disable-line @typescript-eslint/no-explicit-any
children: () => any;
} = $props();
/**

View file

@ -38,7 +38,7 @@ A group of tiles. Places them correctly in a grid.
/**
* Tiles.
*/
children: () => any; // eslint-disable-line @typescript-eslint/no-explicit-any
children: () => any;
} = $props();
// NOTE: to make it usable for small tiles