From 7b6a8bbaab2f115c168d4142e4b13998caab05b1 Mon Sep 17 00:00:00 2001 From: Arindy Date: Mon, 22 Dec 2025 20:45:55 +0100 Subject: [PATCH] Add Pi-hole blocked percentage and date widgets --- apis/pihole/info.go | 3 +-- apis/pihole/pihole.go | 11 ++++++++++- apis/pihole/stats.go | 3 +-- config/config.go | 4 ++-- main.go | 19 ++++++++++++++++++ widgets/date.go | 42 ++++++++++++++++++++++++++++++++++++++++ widgets/piholeblocked.go | 36 ++++++++++++++++++++++++++++++++++ 7 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 widgets/date.go create mode 100644 widgets/piholeblocked.go diff --git a/apis/pihole/info.go b/apis/pihole/info.go index dc8ee5a..1d5bf2a 100644 --- a/apis/pihole/info.go +++ b/apis/pihole/info.go @@ -2,7 +2,6 @@ package pihole import ( "encoding/json" - "log" ) type Version struct { @@ -38,7 +37,7 @@ func (ph *PiHConnector) Version() Version { err := json.Unmarshal(ph.get("info/version"), version) if err != nil { - log.Fatal(err) + version = &Version{} } return *version } diff --git a/apis/pihole/pihole.go b/apis/pihole/pihole.go index 93f3a65..0256e9e 100644 --- a/apis/pihole/pihole.go +++ b/apis/pihole/pihole.go @@ -41,6 +41,9 @@ func (ph *PiHConnector) post(endpoint string, body io.Reader) []byte { } func (ph *PiHConnector) do(method string, endpoint string, body io.Reader) []byte { + if ph.Host == "" { + return make([]byte, 0) + } var requestString = "http://" + ph.Host + "/api/" + endpoint client := &http.Client{} @@ -67,7 +70,12 @@ func (ph *PiHConnector) do(method string, endpoint string, body io.Reader) []byt return respBody } +var connector *PiHConnector + func Connect() PiHConnector { + if connector != nil { + return *connector + } cfg := &configFile{} config.LoadConfig(cfg) client := &http.Client{} @@ -93,8 +101,9 @@ func Connect() PiHConnector { if err != nil { log.Fatal(err) } - return PiHConnector{ + connector = &PiHConnector{ Host: cfg.Pihole.Host, Session: s.Session, } + return *connector } diff --git a/apis/pihole/stats.go b/apis/pihole/stats.go index ddcde94..427eeb1 100644 --- a/apis/pihole/stats.go +++ b/apis/pihole/stats.go @@ -2,7 +2,6 @@ package pihole import ( "encoding/json" - "log" ) type Summary struct { @@ -35,7 +34,7 @@ func (ph *PiHConnector) Summary() Summary { err := json.Unmarshal(ph.get("stats/summary"), summary) if err != nil { - log.Fatal(err) + summary = &Summary{} } return *summary } diff --git a/config/config.go b/config/config.go index 676f28e..f41a6f3 100644 --- a/config/config.go +++ b/config/config.go @@ -8,14 +8,14 @@ import ( func LoadConfig(config interface{}) { if err := toml.Unmarshal(readFile("config.toml"), config); err != nil { - panic(err) + config = nil } } func readFile(path string) []byte { data, err := os.ReadFile(path) if err != nil { - panic(err) + return make([]byte, 0) } return data } diff --git a/main.go b/main.go index 7733724..973b39c 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "context" "github.com/mum4k/termdash" + "github.com/mum4k/termdash/align" "github.com/mum4k/termdash/cell" "github.com/mum4k/termdash/container" "github.com/mum4k/termdash/container/grid" @@ -32,10 +33,12 @@ func initWidgets(ctx context.Context, term *tcell.Terminal) { widgets.Create(ctx, term, widgets.New("Clock", widgets.Clock()), + widgets.New("Date", widgets.Date()), widgets.New("ChangeTitle", widgets.TextInput(titleUpdate, textinput.Label("Update Title: "), textinput.PlaceHolder("New Title"))), widgets.New("Wifi", widgets.WifiQRCode()), widgets.New("Docker", widgets.DockerList()), widgets.New("PiHole", widgets.PiholeStats()), + widgets.New("PiHoleBlocked", widgets.PiholeBlocked()), ) } @@ -56,11 +59,20 @@ func layout() []container.Option { grid.ColWidthPerc(20, grid.RowHeightFixed(8, grid.Widget(widgets.Get["Clock"], + container.AlignHorizontal(align.HorizontalCenter), container.BorderTitle("Time"), container.Border(linestyle.Light), container.BorderColor(cell.ColorWhite), ), ), + grid.RowHeightFixed(3, + grid.Widget(widgets.Get["Date"], + container.AlignHorizontal(align.HorizontalCenter), + container.BorderTitle("Date"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), + ), grid.RowHeightFixed(8, grid.Widget(widgets.Get["PiHole"], container.BorderTitle("pi-hole"), @@ -68,6 +80,13 @@ func layout() []container.Option { container.BorderColor(cell.ColorWhite), ), ), + grid.RowHeightFixed(25, + grid.Widget(widgets.Get["PiHoleBlocked"], + container.BorderTitle("pi-hole (Blocked Percent)"), + container.Border(linestyle.Light), + container.BorderColor(cell.ColorWhite), + ), + ), grid.RowHeightPerc(85, grid.Widget(widgets.Get["empty"]), ), diff --git a/widgets/date.go b/widgets/date.go new file mode 100644 index 0000000..9f00fec --- /dev/null +++ b/widgets/date.go @@ -0,0 +1,42 @@ +package widgets + +import ( + "ArinDash/util" + "context" + "time" + + "github.com/mum4k/termdash/terminal/terminalapi" + "github.com/mum4k/termdash/widgetapi" + "github.com/mum4k/termdash/widgets/text" +) + +type DateOptions struct { +} + +func Date() DateOptions { + widgetOptions["DateOptions"] = createDate + return DateOptions{} +} + +func createDate(ctx context.Context, _ terminalapi.Terminal, _ interface{}) widgetapi.Widget { + widget := util.PanicOnErrorWithResult(text.New()) + + go util.Periodic(ctx, 1*time.Second, func() error { + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + now := time.Now() + if err := widget.Write(now.Format("Monday 2.1.2006"), text.WriteReplace()); err != nil { + panic(err) + } + + case <-ctx.Done(): + return nil + } + } + }) + + return widget +} diff --git a/widgets/piholeblocked.go b/widgets/piholeblocked.go new file mode 100644 index 0000000..19f3bab --- /dev/null +++ b/widgets/piholeblocked.go @@ -0,0 +1,36 @@ +package widgets + +import ( + "ArinDash/apis/pihole" + "ArinDash/util" + "context" + "time" + + "github.com/mum4k/termdash/cell" + "github.com/mum4k/termdash/terminal/terminalapi" + "github.com/mum4k/termdash/widgetapi" + "github.com/mum4k/termdash/widgets/donut" +) + +type PiholeBlockedOptions struct { +} + +func PiholeBlocked() PiholeBlockedOptions { + widgetOptions["PiholeBlockedOptions"] = createPiholeBlocked + return PiholeBlockedOptions{} +} + +func createPiholeBlocked(ctx context.Context, _ terminalapi.Terminal, _ interface{}) widgetapi.Widget { + widget := util.PanicOnErrorWithResult(donut.New(donut.CellOpts(cell.FgColor(cell.ColorRed), cell.Blink()), donut.HolePercent(20), donut.ShowTextProgress())) + + ph := pihole.Connect() + go util.Periodic(ctx, 1*time.Minute, func() error { + summary := ph.Summary() + if err := widget.Percent(int(summary.Queries.PercentBlocked)); err != nil { + return nil + } + return nil + }) + + return widget +}