summaryrefslogtreecommitdiff
path: root/src/services/weather.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/services/weather.ts')
-rw-r--r--src/services/weather.ts388
1 files changed, 0 insertions, 388 deletions
diff --git a/src/services/weather.ts b/src/services/weather.ts
deleted file mode 100644
index d51e7fc..0000000
--- a/src/services/weather.ts
+++ /dev/null
@@ -1,388 +0,0 @@
-import { weatherIcons } from "@/utils/icons";
-import { notify } from "@/utils/system";
-import {
- execAsync,
- GLib,
- GObject,
- interval,
- property,
- readFileAsync,
- register,
- writeFileAsync,
- type Time,
-} from "astal";
-import { weather as config } from "config";
-
-export interface WeatherCondition {
- text: string;
- icon: string;
- code: number;
-}
-
-interface _WeatherState {
- temp_c: number;
- temp_f: number;
- is_day: number;
- condition: WeatherCondition;
- wind_mph: number;
- wind_kph: number;
- wind_degree: number;
- wind_dir: "N" | "NE" | "E" | "SE" | "S" | "SW" | "W" | "NW";
- pressure_mb: number;
- pressure_in: number;
- precip_mm: number;
- precip_in: number;
- humidity: number;
- cloud: number;
- feelslike_c: number;
- feelslike_f: number;
- windchill_c: number;
- windchill_f: number;
- heatindex_c: number;
- heatindex_f: number;
- dewpoint_c: number;
- dewpoint_f: number;
- vis_km: number;
- vis_miles: number;
- uv: number;
- gust_mph: number;
- gust_kph: number;
-}
-
-export interface WeatherCurrent extends _WeatherState {
- last_updated_epoch: number;
- last_updated: string;
-}
-
-export interface WeatherHour extends _WeatherState {
- time_epoch: number;
- time: string;
-}
-
-export interface WeatherDay {
- date: string;
- date_epoch: number;
- day: {
- maxtemp_c: number;
- maxtemp_f: number;
- mintemp_c: number;
- mintemp_f: number;
- avgtemp_c: number;
- avgtemp_f: number;
- maxwind_mph: number;
- maxwind_kph: number;
- totalprecip_mm: number;
- totalprecip_in: number;
- totalsnow_cm: number;
- avgvis_km: number;
- avgvis_miles: number;
- avghumidity: number;
- daily_will_it_rain: number;
- daily_chance_of_rain: number;
- daily_will_it_snow: number;
- daily_chance_of_snow: number;
- condition: WeatherCondition;
- uv: number;
- };
- astro: {
- sunrise: string;
- sunset: string;
- moonrise: string;
- moonset: string;
- moon_phase: string;
- moon_illumination: string;
- is_moon_up: number;
- is_sun_up: number;
- };
- hour: WeatherHour[];
-}
-
-export interface WeatherLocation {
- name: string;
- region: string;
- country: string;
- lat: number;
- lon: number;
- tz_id: string;
- localtime_epoch: number;
- localtime: string;
-}
-
-export interface WeatherData {
- current: WeatherCurrent;
- forecast: { forecastday: WeatherDay[] };
- location: WeatherLocation;
-}
-
-const DEFAULT_STATE: _WeatherState = {
- temp_c: 0,
- temp_f: 0,
- is_day: 0,
- condition: { text: "", icon: "", code: 0 },
- wind_mph: 0,
- wind_kph: 0,
- wind_degree: 0,
- wind_dir: "N",
- pressure_mb: 0,
- pressure_in: 0,
- precip_mm: 0,
- precip_in: 0,
- humidity: 0,
- cloud: 0,
- feelslike_c: 0,
- feelslike_f: 0,
- windchill_c: 0,
- windchill_f: 0,
- heatindex_c: 0,
- heatindex_f: 0,
- dewpoint_c: 0,
- dewpoint_f: 0,
- vis_km: 0,
- vis_miles: 0,
- uv: 0,
- gust_mph: 0,
- gust_kph: 0,
-};
-
-const DEFAULT: WeatherData = {
- current: {
- last_updated_epoch: 0,
- last_updated: "",
- ...DEFAULT_STATE,
- },
- forecast: {
- forecastday: [
- {
- date: "",
- date_epoch: 0,
- day: {
- maxtemp_c: 0,
- maxtemp_f: 0,
- mintemp_c: 0,
- mintemp_f: 0,
- avgtemp_c: 0,
- avgtemp_f: 0,
- maxwind_mph: 0,
- maxwind_kph: 0,
- totalprecip_mm: 0,
- totalprecip_in: 0,
- totalsnow_cm: 0,
- avgvis_km: 0,
- avgvis_miles: 0,
- avghumidity: 0,
- daily_will_it_rain: 0,
- daily_chance_of_rain: 0,
- daily_will_it_snow: 0,
- daily_chance_of_snow: 0,
- condition: { text: "", icon: "", code: 0 },
- uv: 0,
- },
- astro: {
- sunrise: "",
- sunset: "",
- moonrise: "",
- moonset: "",
- moon_phase: "",
- moon_illumination: "",
- is_moon_up: 0,
- is_sun_up: 0,
- },
- hour: Array.from({ length: 24 }, () => ({
- time_epoch: 0,
- time: "",
- ...DEFAULT_STATE,
- })),
- },
- ],
- },
- location: {
- name: "",
- region: "",
- country: "",
- lat: 0,
- lon: 0,
- tz_id: "",
- localtime_epoch: 0,
- localtime: "",
- },
-};
-
-@register({ GTypeName: "Weather" })
-export default class Weather extends GObject.Object {
- static instance: Weather;
- static get_default() {
- if (!this.instance) this.instance = new Weather();
-
- return this.instance;
- }
-
- readonly #cache: string = `${CACHE}/weather.json`;
- #notified = false;
-
- #data: WeatherData = DEFAULT;
-
- #interval: Time | null = null;
-
- @property(Object)
- get raw() {
- return this.#data;
- }
-
- @property(Object)
- get current() {
- return this.#data.current;
- }
-
- @property(Object)
- get forecast() {
- return this.#data.forecast.forecastday[0].hour;
- }
-
- @property(Object)
- get location() {
- return this.#data.location;
- }
-
- @property(String)
- get condition() {
- return this.#data.current.condition.text;
- }
-
- @property(String)
- get temperature() {
- return this.getTemp(this.#data.current);
- }
-
- @property(String)
- get wind() {
- return `${Math.round(this.#data.current[`wind_${config.imperial.get() ? "m" : "k"}ph`])} ${
- config.imperial.get() ? "m" : "k"
- }ph`;
- }
-
- @property(String)
- get rainChance() {
- return this.#data.forecast.forecastday[0].day.daily_chance_of_rain + "%";
- }
-
- @property(String)
- get icon() {
- return this.getIcon(this.#data.current.condition.text);
- }
-
- @property(String)
- get tempIcon() {
- return this.getTempIcon(this.#data.current.temp_c);
- }
-
- @property(String)
- get tempColour() {
- return this.getTempDesc(this.#data.current.temp_c);
- }
-
- getIcon(status: string) {
- let query = status.trim().toLowerCase().replaceAll(" ", "_");
- if (!this.#data.current.is_day && query + "_night" in weatherIcons) query += "_night";
- return weatherIcons[query] ?? weatherIcons.warning;
- }
-
- getTemp(data: _WeatherState) {
- return `${Math.round(data[`temp_${config.imperial.get() ? "f" : "c"}`])}°${config.imperial.get() ? "F" : "C"}`;
- }
-
- getTempIcon(temp: number) {
- if (temp >= 40) return "";
- if (temp >= 30) return "";
- if (temp >= 20) return "";
- if (temp >= 10) return "";
- return "";
- }
-
- getTempDesc(temp: number) {
- if (temp >= 40) return "burning";
- if (temp >= 30) return "hot";
- if (temp >= 20) return "normal";
- if (temp >= 10) return "cold";
- return "freezing";
- }
-
- #notify() {
- this.notify("raw");
- this.notify("current");
- this.notify("forecast");
- this.notify("location");
- this.notify("condition");
- this.notify("temperature");
- this.notify("wind");
- this.notify("rain-chance");
- this.notify("icon");
- this.notify("temp-icon");
- this.notify("temp-colour");
- }
-
- async getWeather() {
- const location = config.location || JSON.parse(await execAsync("curl ipinfo.io")).city;
- const opts = `key=${config.apiKey.get()}&q=${location}&days=1&aqi=no&alerts=no`;
- const url = `https://api.weatherapi.com/v1/forecast.json?${opts}`;
- return JSON.parse(await execAsync(["curl", url]));
- }
-
- async updateWeather() {
- if (!config.apiKey.get()) {
- if (!this.#notified) {
- notify({
- summary: "Weather API key required",
- body: `A weather API key is required to get weather data. Get one from https://www.weatherapi.com.`,
- icon: "dialog-warning-symbolic",
- urgency: "critical",
- actions: {
- "Get API key": () => execAsync(`app2unit -O 'https://www.weatherapi.com'`).catch(print),
- },
- });
- this.#notified = true;
- }
- return;
- }
-
- if (GLib.file_test(this.#cache, GLib.FileTest.EXISTS)) {
- const cache = await readFileAsync(this.#cache);
- const cache_data: WeatherData = JSON.parse(cache);
- if (cache_data.location.localtime_epoch * 1000 + config.interval.get() > Date.now()) {
- if (JSON.stringify(this.#data) !== cache) {
- this.#data = cache_data;
- this.#notify();
- }
- return;
- }
- }
-
- try {
- const data = await this.getWeather();
- this.#data = data;
- writeFileAsync(this.#cache, JSON.stringify(data)).catch(console.error); // Catch here so it doesn't propagate
- } catch (e) {
- console.error("Error getting weather:", e);
- this.#data = DEFAULT;
- }
- this.#notify();
- }
-
- constructor() {
- super();
-
- this.updateWeather().catch(console.error);
- this.#interval = interval(config.interval.get(), () => this.updateWeather().catch(console.error));
-
- config.apiKey.subscribe(() => this.updateWeather());
-
- config.interval.subscribe(i => {
- this.#interval?.cancel();
- this.#interval = interval(i, () => this.updateWeather().catch(console.error));
- });
-
- config.imperial.subscribe(() => {
- this.notify("temperature");
- this.notify("wind");
- });
- }
-}