initial commit

This commit is contained in:
Cato 2025-07-01 22:40:05 +02:00
commit 885ff3b928
11 changed files with 367 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/gomod2nix-template

89
awl.go Normal file
View file

@ -0,0 +1,89 @@
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
)
const AWL_URL string = "https://buergerportal.awl-neuss.de/api/v1/calendar"
func GetStreetNumbers() (map[string]int, error) {
url := AWL_URL + "/townarea-streets"
response, err := http.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
content, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
var streets []struct {
Number int `json:"strasseNummer"`
Name string `json:"strasseBezeichnung"`
}
err = json.Unmarshal(content, &streets)
if err != nil {
return nil, err
}
nameToNumber := make(map[string]int, len(streets))
for _, street := range streets {
name := strings.ToLower(street.Name)
name = strings.Replace(name, " ", "-", -1)
name = strings.Replace(name, "--", "-", -1)
nameToNumber[name] = street.Number
}
return nameToNumber, nil
}
func AwlTomorrow(street, home int) ([]string, error) {
startDate := time.Now().AddDate(0, 0, 1)
startDateFmt := startDate.Format("Jan 02 2006")
requestUrl := fmt.Sprintf(AWL_URL + "?startMonth=%s&streetNum=%d&homeNumber=%d", url.QueryEscape(startDateFmt), street, home)
response, err := http.Get(requestUrl)
if err != nil {
return nil, err
}
defer response.Body.Close()
content, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
var jsonBody map[string]map[string][]string
err = json.Unmarshal(content, &jsonBody)
if err != nil {
return nil, fmt.Errorf("could not parse json:\n%s\n%s", err.Error(), content)
}
if len(jsonBody) != 1 {
return nil, fmt.Errorf("unexpected awl response:\n%s", string(content))
}
currentMonth := fmt.Sprintf("%d-%d", startDate.Month()-1, startDate.Year())
currentDay := startDate.Format("2")
month, ok := jsonBody[currentMonth]
if !ok {
return nil, fmt.Errorf("could not access month (%s):\n%s", currentMonth, string(content))
}
day, ok := month[currentDay]
if !ok {
return nil, fmt.Errorf("could not access day (%s):\n%s", currentDay, string(content))
}
return day, nil
}

21
default.nix Normal file
View file

@ -0,0 +1,21 @@
{ pkgs ? (
let
inherit (builtins) fetchTree fromJSON readFile;
inherit ((fromJSON (readFile ./flake.lock)).nodes) nixpkgs gomod2nix;
in
import (fetchTree nixpkgs.locked) {
overlays = [
(import "${fetchTree gomod2nix.locked}/overlay.nix")
];
}
)
, buildGoApplication ? pkgs.buildGoApplication
}:
buildGoApplication {
pname = "awl-ntfy";
version = "0.1";
pwd = ./.;
src = ./.;
modules = ./gomod2nix.toml;
}

85
flake.lock generated Normal file
View file

@ -0,0 +1,85 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1750314194,
"narHash": "sha256-SjpXWEeB+UIMzuCAF94PuyAXpJdnBLF45JvI6o4wKIU=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "a5f75f563748599d448a4a076816041d7b0fc07e",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "gomod2nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1751271578,
"narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"gomod2nix": "gomod2nix",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

31
flake.nix Normal file
View file

@ -0,0 +1,31 @@
{
description = "A basic gomod2nix flake";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.gomod2nix = {
url = "github:nix-community/gomod2nix";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
};
};
outputs = { self, nixpkgs, flake-utils, gomod2nix }:
(flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = nixpkgs.legacyPackages.${system};
callPackage = pkgs.callPackage;
in
{
packages.default = callPackage ./. {
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
};
devShells.default = callPackage ./shell.nix {
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;
};
})
);
}

8
go.mod Normal file
View file

@ -0,0 +1,8 @@
module catos.directory/tasks/awl-ntfy
go 1.24.2
require (
github.com/alexflint/go-arg v1.5.1 // indirect
github.com/alexflint/go-scalar v1.2.0 // indirect
)

7
go.sum Normal file
View file

@ -0,0 +1,7 @@
github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8Y=
github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8=
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=

3
gomod2nix.toml Normal file
View file

@ -0,0 +1,3 @@
schema = 1
[mod]

52
main.go Normal file
View file

@ -0,0 +1,52 @@
package main
import (
"fmt"
"os"
arg "github.com/alexflint/go-arg"
)
func main() {
var args struct {
Street string `arg:"positional,required"`
Home int `arg:"positional,required"`
}
parser, err := arg.NewParser(arg.Config{}, &args)
if err != nil {
fmt.Println(err)
return
}
parser.MustParse(os.Args[1:])
streetNumbers, err := GetStreetNumbers()
if err != nil {
fmt.Println(err)
_ = SendErr(args.Street, err)
return
}
streetNumber, ok := streetNumbers[args.Street]
if !ok {
fmt.Println("street could not be found:", args.Street)
}
tomorrow, err := AwlTomorrow(streetNumber, args.Home)
if err != nil {
fmt.Println(err)
_ = SendErr(args.Street, err)
return
}
if len(tomorrow) == 0 {
return
}
err = SendAwlNotification(args.Street, tomorrow)
if err != nil {
fmt.Println(err)
_ = SendErr(args.Street, err)
return
}
}

46
ntfy.go Normal file
View file

@ -0,0 +1,46 @@
package main
import (
"fmt"
"net/http"
"strings"
)
func SendAwlNotification(channel string, binColors []string) error {
var bins = make([]string, 0, 5)
for _, color := range binColors {
switch color {
case "pink":
bins = append(bins, "🟣 Pink")
case "gelb":
bins = append(bins, "🟡 Gelb")
case "blau":
bins = append(bins, "🔵 Blau")
case "grau":
bins = append(bins, "⚫ Grau")
case "braun":
bins = append(bins, "🟤 Braun")
}
}
var message string
if len(bins) == 1 {
message = "Morgen wird folgende Tonne abgeholt: "
} else {
message = "Morgen werden folgende Tonnen abgeholt: "
}
message += strings.Join(bins, ", ")
return SendNotification(channel, message)
}
func SendNotification(channel, message string) error {
topic := fmt.Sprintf("https://ntfy.sh/awl_neuss_%s_err", channel)
_, err := http.Post(topic, "text/plain", strings.NewReader(message))
return err
}
func SendErr(channel string, err error) error {
topic := fmt.Sprintf("https://ntfy.sh/awl_neuss_%s_err", channel)
_, err = http.Post(topic, "text/plain", strings.NewReader(err.Error()))
return err
}

24
shell.nix Normal file
View file

@ -0,0 +1,24 @@
{ pkgs ? (
let
inherit (builtins) fetchTree fromJSON readFile;
inherit ((fromJSON (readFile ./flake.lock)).nodes) nixpkgs gomod2nix;
in
import (fetchTree nixpkgs.locked) {
overlays = [
(import "${fetchTree gomod2nix.locked}/overlay.nix")
];
}
)
, mkGoEnv ? pkgs.mkGoEnv
, gomod2nix ? pkgs.gomod2nix
}:
let
goEnv = mkGoEnv { pwd = ./.; };
in
pkgs.mkShell {
packages = [
goEnv
gomod2nix
];
}