diff options
author | awy <awy@awy.one> | 2025-08-24 04:55:06 +0300 |
---|---|---|
committer | awy <awy@awy.one> | 2025-08-24 04:55:06 +0300 |
commit | f0f0a3dacc0e6894e83d42ab7788771b33b701b5 (patch) | |
tree | d53bd0891d11650c299314509f9a6678501b7857 | |
parent | d660f875554a25bad0f107ee8ca694a8ad9472ef (diff) |
stweath
-rw-r--r-- | Makefile | 3 | ||||
-rwxr-xr-x | sb-weather | 82 | ||||
-rw-r--r-- | src/stweath.c | 215 |
3 files changed, 218 insertions, 82 deletions
@@ -17,6 +17,9 @@ $(BINDIR)/stmusic: $(SRCDIR)/stmusic.c $(BINDIR)/sttorrent: $(SRCDIR)/sttorrent.c $(CC) $(CFLAGS) -o $@ $(SRCDIR)/cjson/cJSON.c $< -lcurl +$(BINDIR)/stweath: $(SRCDIR)/stweath.c + $(CC) $(CFLAGS) -o $@ $(SRCDIR)/cjson/cJSON.c $< -lcurl + $(BINDIR)/%: $(SRCDIR)/%.c $(CC) $(CFLAGS) -o $@ $< diff --git a/sb-weather b/sb-weather deleted file mode 100755 index f3a5aca..0000000 --- a/sb-weather +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/sh -arg=$1 -report=~/.cache/weather_report.json - -ifinstalled jq - -# Get a weather report from 'wttr.in' and save it locally. -getforecast() { { rg -q -m1 '^up$' /sys/class/net/w*/operstate || rg -q -m1 '^up$' /sys/class/net/e*/operstate; } && - curl -sf "wttr.in/?format=j1" --output "$report" && touch "$report" -} - -# Forecast should be updated only once a day. -checkforecast() { - [ "$(stat -c %y "$report" 2>/dev/null | - cut -d' ' -f1)" = "$(date '+%Y-%m-%d')" ] -} - -# Function to get weather emoji from code -get_weather_emoji() { - local code="$1" - grep "^$code " ~/.local/share/extras/weather_codes | awk '{print $2}' -} - -showweather(){ - temp=$(jq -r '.current_condition[0].temp_C' $report) - code=$(jq -r '.current_condition[0].weatherCode' $report) - rainchance=$(jq '.weather[0].hourly[0].chanceofrain | tonumber' $report) - - emoji=$(get_weather_emoji "$code") - case "$arg" in - weather) - case 1 in - $((temp >= 30)) ) class="very_hot" ;; - $((temp >= 26)) ) class="hot" ;; - $((temp >= 21)) ) class="warm" ;; - $((temp >= 16)) ) class="mild" ;; - $((temp >= 11)) ) class="cool" ;; - $((temp >= 6)) ) class="chilly" ;; - $((temp >= 0)) ) class="cold" ;; - $((temp < 0)) ) class="below_zero" ;; - * ) echo unavailable && exit ;; - esac - output="$emoji$temp°C" - ;; - rain) - case 1 in - $((rainchance >= 70)) ) class="high" ;; - $((rainchance >= 45)) ) class="mid" ;; - $((rainchance > 0)) ) class="low" ;; - $((rainchance <= 0)) ) printf '' && exit ;; - * ) echo unavailable && exit ;; - esac - output="$rainchance%" - ;; - *) - echo "Usage: $0 {weather|rain}" - exit 1 - ;; - esac - printf '{"text": "%s", "class": "%s" }' "$output" "$class" -} - -case $BLOCK_BUTTON in - 2) getforecast && showweather ;; - 3) notify-send " Weather module" "\- Middle click to update forecast. -: Chance of rain/snow -: Current temperature" ;; - 8) setsid -f "$TERMINAL" -e "$EDITOR" "$0" >/dev/null 2>&1 ;; -esac - -# shellcheck disable=SC2015 -checkforecast && showweather || - ( flock -n 9 && - ( tries=0; while [ $tries -ne 100 ]; do - getforecast && break || - { tries=$((tries+1)); sleep .1; } - done - ! checkforecast && - until getforecast; do sleep 60; done - pkill -RTMIN+5 "${STATUSBAR:-waybar}" - ) & - echo ) 9>"${XDG_RUNTIME_DIR}/sb-forecast.lock" diff --git a/src/stweath.c b/src/stweath.c new file mode 100644 index 0000000..6e5bef3 --- /dev/null +++ b/src/stweath.c @@ -0,0 +1,215 @@ +/* Copyright (C) 2025 awy <awy@awy.one> + + stweath is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, + either version 3 of the License, or (at your option) any later version. + + stweath is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with stweath. If not, see + <https://www.gnu.org/licenses/>. */ + +#include <curl/curl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include "cjson/cJSON.h" + +int +getforecast(char *path) +{ + FILE *report; + CURL* handle; + CURLcode res; + + report = fopen(path, "w"); + if (!report) { return 1; } + + handle = curl_easy_init(); + + if (!handle) { + fclose(report); + return 1; + } + + curl_easy_setopt(handle, CURLOPT_URL, "https://wttr.in/?format=j1"); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, report); + + res = curl_easy_perform(handle); + + if (res != CURLE_OK) { + fclose(report); + return 1; + } + + curl_easy_cleanup(handle); + + fclose(report); + return 0; +} + +int +showforecast(char *path) +{ + long size; + char *data; + char *icon; + cJSON *root, *temp, *wcode, *rain; + FILE *report; + + report = fopen(path, "rb"); + if (!report) { return 1; } + + fseek(report, 0, SEEK_END); + size = ftell(report); + fseek(report, 0, SEEK_SET); + + data = malloc(size + 1); + if (!data) { + perror("malloc"); + fclose(report); + return 1; + } + fread(data, 1, size, report); + data[size] = '\0'; + fclose(report); + + root = cJSON_Parse(data); + free(data); + if (!root) { return 1; } + + rain = cJSON_GetArrayItem(cJSON_GetObjectItem(root, "weather"), 0); + rain = cJSON_GetArrayItem(cJSON_GetObjectItem(rain, "hourly"), 0); + rain = cJSON_GetObjectItem(rain, "chanceofrain"); + temp = cJSON_GetObjectItem(root, "current_condition"); + temp = cJSON_GetArrayItem(temp, 0); + wcode = cJSON_GetObjectItem(temp, "weatherCode"); + temp = cJSON_GetObjectItem(temp, "temp_C"); + + switch (atoi(wcode->valuestring)) { + case 113: icon = ""; break; + case 116: icon = ""; break; + case 119: + case 122: + case 143: + case 248: + case 260: + icon = ""; break; + case 176: + case 179: + case 182: + case 185: + case 263: + case 266: + case 281: + case 284: + case 293: + case 296: + case 299: + case 302: + case 305: + case 308: + case 311: + case 314: + case 317: + case 350: + case 353: + case 356: + case 359: + case 362: + case 365: + case 368: + case 392: + icon = ""; break; + case 200: icon = ""; break; + case 227: + case 230: + case 320: + case 323: + case 326: + case 374: + case 377: + case 386: + case 389: + icon = ""; break; + case 329: + case 332: + case 335: + case 338: + case 371: + case 395: + icon = ""; break; + default: icon = "❓"; break; + } + + if (atoi(rain->valuestring) != 0) { + printf(" %s%% ", rain->valuestring); + } + printf("%s %s°C", icon, temp->valuestring); + + cJSON_Delete(root); + return 0; +} + +int +checkforecast(char *path) +{ + time_t now; + char *buff; + struct stat st; + int tries, force; + + /* Check if there is WEATHERFORCEUPDATE + environment variable */ + force = 0; + buff = getenv("WEATHERFORCEUPDATE"); + if (buff && buff[0] == '1') { force = 1; } + + if (stat(path, &st) != 0) { return 1; } + + now = time(NULL); + if (now == ((time_t)-1)) { return 1; } + + /* Check if 30 mins passed + then get new forecast */ + if (((now - st.st_mtime) >= 1800) || force) { + tries = 0; + /* Try 100 fast retries */ + while (tries < 100) { + if(getforecast(path) == 0) { + break; + } + tries++; + sleep(1); + } + } + + showforecast(path); + return 0; +} + +int +main(void) +{ + char *path; + + path = getenv("XDG_CACHE_HOME"); + if (!path) { puts("XDG_CACHE_HOME is not set"); return 1; } + strcat(path, "/weatherreport.json"); + + curl_global_init(CURL_GLOBAL_ALL); + + checkforecast(path); + + curl_global_cleanup(); + return 0; +} |