1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00
Files
DankMaterialShell/Services/WeatherService.qml
2025-07-10 19:11:35 -04:00

146 lines
4.3 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Io
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
property var weather: ({
available: false,
temp: 0,
tempF: 0,
city: "",
wCode: "113",
humidity: 0,
wind: "",
sunrise: "06:00",
sunset: "18:00",
uv: 0,
pressure: 0
})
// Weather icon mapping (based on wttr.in weather codes)
property var weatherIcons: ({
"113": "clear_day",
"116": "partly_cloudy_day",
"119": "cloud",
"122": "cloud",
"143": "foggy",
"176": "rainy",
"179": "rainy",
"182": "rainy",
"185": "rainy",
"200": "thunderstorm",
"227": "cloudy_snowing",
"230": "snowing_heavy",
"248": "foggy",
"260": "foggy",
"263": "rainy",
"266": "rainy",
"281": "rainy",
"284": "rainy",
"293": "rainy",
"296": "rainy",
"299": "rainy",
"302": "weather_hail",
"305": "rainy",
"308": "weather_hail",
"311": "rainy",
"314": "rainy",
"317": "rainy",
"320": "cloudy_snowing",
"323": "cloudy_snowing",
"326": "cloudy_snowing",
"329": "snowing_heavy",
"332": "snowing_heavy",
"335": "snowing_heavy",
"338": "snowing_heavy",
"350": "rainy",
"353": "rainy",
"356": "weather_hail",
"359": "weather_hail",
"362": "rainy",
"365": "weather_hail",
"368": "cloudy_snowing",
"371": "snowing_heavy",
"374": "weather_hail",
"377": "weather_hail",
"386": "thunderstorm",
"389": "thunderstorm",
"392": "snowing_heavy",
"395": "snowing_heavy"
})
function getWeatherIcon(code) {
return weatherIcons[code] || "cloud"
}
Process {
id: weatherFetcher
command: ["bash", "-c", "curl -s 'wttr.in/?format=j1'"]
running: false
stdout: StdioCollector {
onStreamFinished: {
const raw = text.trim()
if (!raw || raw[0] !== "{") {
console.warn("No valid weather data received")
root.weather.available = false
return
}
try {
const data = JSON.parse(raw)
const current = data.current_condition?.[0] || {}
const location = data.nearest_area?.[0] || {}
const astronomy = data.weather?.[0]?.astronomy?.[0] || {}
if (!Object.keys(current).length || !Object.keys(location).length) {
throw new Error("Required fields missing")
}
root.weather = {
available: true,
temp: Number(current.temp_C) || 0,
tempF: Number(current.temp_F) || 0,
city: location.areaName?.[0]?.value || "Unknown",
wCode: current.weatherCode || "113",
humidity: Number(current.humidity) || 0,
wind: `${current.windspeedKmph || 0} km/h`,
sunrise: astronomy.sunrise || "06:00",
sunset: astronomy.sunset || "18:00",
uv: Number(current.uvIndex) || 0,
pressure: Number(current.pressure) || 0
}
console.log("Weather updated:", root.weather.city,
`${root.weather.temp}°C`)
} catch (e) {
console.warn("Failed to parse weather data:", e.message)
root.weather.available = false
}
}
}
onExited: (exitCode) => {
if (exitCode !== 0) {
console.warn("Weather fetch failed with exit code:", exitCode)
root.weather.available = false
}
}
}
Timer {
interval: 600000 // 10 minutes
running: true
repeat: true
triggeredOnStart: true
onTriggered: {
weatherFetcher.running = true
}
}
}