# slackware-changelog A widget for a [Homepage](https://gethomepage.dev) dashboard, one of the modules under `homepage-modules/`. Siblings share the shape described below. ## Shape of a module Homepage's `customapi` widget fetches JSON and maps fields to labels. It cannot parse text, cannot do arithmetic, and refetches on every refresh interval. So each module is a small stdlib Python HTTP service on localhost that does the parsing and caching, plus: - `.py` - the service, single file, stdlib only, executable - `test_.py` - self-check, fakes the upstream, prints `ok` - `.service` - systemd unit, `DynamicUser=yes`, config via `Environment=` - `homepage-services.yaml` / `homepage-settings.yaml` - snippets to merge No dependencies. No framework. `ThreadingHTTPServer` and `urllib`. ## This module Serves the latest Slackware -current ChangeLog entry on `127.0.0.1:8098`. Endpoints: `/latest` (counts and summary), `/top` (the first `TOP_N` packages as flat fields), `/packages` (every package with its action), `/entry` (HTML page of the entry), `/refresh` (bypass the cache). ### Why /top exists `customapi` maps a fixed list of field names to labels. It cannot iterate an array and cannot scroll, so a JSON list of packages renders as nothing. `/top` flattens the first `TOP_N` into `pkg1`, `pkg2`, ... which the widget can map one per row, and appends a `... and N more` row in the next slot when the entry is longer. The card links to the ChangeLog for the rest. Mapping more `pkgN` fields than the entry has packages is harmless: Homepage skips a field that is absent. So the snippet maps a fixed 9 rows regardless of how many that day's entry holds. ### ChangeLog format The file is reverse-chronological. Entries are separated by a `+--------+` line, so the latest entry is everything before the first separator. Inside an entry: ``` Mon Sep 7 22:56:39 UTC 2026 a/util-linux-2.42.3-x86_64-1.txz: Upgraded. This update fixes bugs and security issues. (* Security fix *) l/cryptopp-8.9.0-x86_64-3.txz: Rebuilt. Fixed library location. Thanks to Petri Kaukasoina. ``` Gotcha: a package line is identified by **starting at column 0**, not by ending in a period. Note lines are indented and frequently end in a period too ("Thanks to Petri Kaukasoina."), so a period-based regex counts prose as packages. The test asserts this specific case. Actions seen: `Upgraded`, `Rebuilt`, `Added`, `Removed`. The parser counts whatever word it finds rather than matching a fixed list, so a new action verb shows up in `summary` instead of vanishing. Security fixes are marked by the literal `(* Security fix *)` on its own indented line. CVE ids appear in the notes as cve.org URLs. ### Caching `CACHE_TTL` (default 1800s) governs upstream fetches; the widget's `refreshInterval` only redraws. A failed refresh keeps the previous entry and adds a `stale` field with the error, so an unreachable mirror degrades to an old entry rather than a blank card. `/refresh` forces a fetch but obeys the same fallback. ### Rendering `/entry` escapes everything from the ChangeLog with `html.escape` before it reaches the page. Upstream text is not trusted markup; the test asserts no `