From c9f3bf46f0de09edb796e35f3dcff349febf75c9 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Fri, 24 Jul 2026 10:32:28 +0200 Subject: dayinfo: show feast/day name + colour (modern niedziela + traditional missalemeum) in cli/tui/web; v0.5.0 --- internal/tradlit/tradlit.go | 63 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 13 deletions(-) (limited to 'internal/tradlit/tradlit.go') diff --git a/internal/tradlit/tradlit.go b/internal/tradlit/tradlit.go index a7b53bc..b464e56 100644 --- a/internal/tradlit/tradlit.go +++ b/internal/tradlit/tradlit.go @@ -34,29 +34,66 @@ var citationRe = regexp.MustCompile(`\*([^*\n]+)\*`) // apiResponse mirrors the shape of the missalemeum proper-of-the-day API: // a single-element list of { info, sections }. type apiResponse struct { - Info struct { - Title string `json:"title"` - } `json:"info"` + Info apiInfo `json:"info"` Sections []apiSection `json:"sections"` } +// apiInfo mirrors the missalemeum API's "info" object: the day's celebration +// title, its temporal context ("tempora"), and its liturgical colour code(s) +// -- see dayInfoFromAPI, which turns it into a liturgy.DayInfo. +type apiInfo struct { + Title string `json:"title"` + Tempora string `json:"tempora"` + Colors []string `json:"colors"` +} + type apiSection struct { ID string `json:"id"` Label string `json:"label"` Body [][]string `json:"body"` } +// tradColours maps missalemeum's single-letter liturgical colour codes to +// DayInfo's normalized colour names; a code not listed here (or an empty +// Colors list) leaves DayInfo.Colour "". +var tradColours = map[string]string{ + "w": "white", + "r": "red", + "v": "violet", + "g": "green", + "p": "rose", +} + +// dayInfoFromAPI turns a response's info object into a liturgy.DayInfo: +// Title -> Name, Tempora -> Season, and the first Colors code -> Colour via +// tradColours (unknown/missing -> ""). A zero-value apiInfo (no "info" key +// in the response) yields a zero DayInfo. +func dayInfoFromAPI(info apiInfo) liturgy.DayInfo { + colour := "" + if len(info.Colors) > 0 { + colour = tradColours[strings.ToLower(info.Colors[0])] + } + return liturgy.DayInfo{ + Name: info.Title, + Season: info.Tempora, + Colour: colour, + } +} + // Parse decodes a missalemeum proper-of-the-day API response body into -// liturgy.Sections. Sections with an empty id or empty body are skipped. -func Parse(jsonBody []byte) ([]liturgy.Section, error) { +// liturgy.Sections plus the day's liturgical identity (its "info" object, +// see dayInfoFromAPI). Sections with an empty id or empty body are skipped. +func Parse(jsonBody []byte) ([]liturgy.Section, liturgy.DayInfo, error) { var resp []apiResponse if err := json.Unmarshal(jsonBody, &resp); err != nil { - return nil, fmt.Errorf("tradlit: parse: %w", err) + return nil, liturgy.DayInfo{}, fmt.Errorf("tradlit: parse: %w", err) } if len(resp) == 0 { - return nil, fmt.Errorf("tradlit: parse: empty response") + return nil, liturgy.DayInfo{}, fmt.Errorf("tradlit: parse: empty response") } + info := dayInfoFromAPI(resp[0].Info) + var out []liturgy.Section for _, sec := range resp[0].Sections { if sec.ID == "" || len(sec.Body) == 0 || len(sec.Body[0]) == 0 { @@ -85,7 +122,7 @@ func Parse(jsonBody []byte) ([]liturgy.Section, error) { Paragraphs: [][]string{lines}, }) } - return out, nil + return out, info, nil } // cachePath returns where Load caches a (date, lang) day's raw API response: @@ -108,7 +145,7 @@ func cachePath(date, lang string) string { // the cache path (best-effort -- a cache-write failure never fails the // request) before being parsed. On HTTP 404 (no propers published for // that date) it returns a clear error and writes nothing to the cache. -func Load(date, lang string, offline bool) ([]liturgy.Section, error) { +func Load(date, lang string, offline bool) ([]liturgy.Section, liturgy.DayInfo, error) { if offline { return loadCached(date, lang) } @@ -116,20 +153,20 @@ func Load(date, lang string, offline bool) ([]liturgy.Section, error) { } // loadCached implements Load's offline path. -func loadCached(date, lang string) ([]liturgy.Section, error) { +func loadCached(date, lang string) ([]liturgy.Section, liturgy.DayInfo, error) { body, err := os.ReadFile(cachePath(date, lang)) if err != nil { - return nil, fmt.Errorf("tradlit: no cached traditional propers for %s (%s); view it online or run 'lectio update' first", date, lang) + return nil, liturgy.DayInfo{}, fmt.Errorf("tradlit: no cached traditional propers for %s (%s); view it online or run 'lectio update' first", date, lang) } return Parse(body) } // loadLive implements Load's online path: fetch, best-effort cache the raw // body, then parse. -func loadLive(date, lang string) ([]liturgy.Section, error) { +func loadLive(date, lang string) ([]liturgy.Section, liturgy.DayInfo, error) { body, err := fetch(date, lang) if err != nil { - return nil, err + return nil, liturgy.DayInfo{}, err } writeCache(date, lang, body) return Parse(body) -- cgit v1.3