diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 12:52:13 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 12:52:13 +0200 |
| commit | 44472bbe31475a3c672ae003d928d7caffb4b50a (patch) | |
| tree | e74bae03c61b62479ef4f68b046e3345618933c8 /internal/readings/offline.go | |
| parent | 626f2275438a37e5cd2efb5964281b9bef5ce8cc (diff) | |
| parent | 7b220084cf3951c8cde0582efdfcf628afc64336 (diff) | |
| download | lectio-44472bbe31475a3c672ae003d928d7caffb4b50a.tar.gz lectio-44472bbe31475a3c672ae003d928d7caffb4b50a.zip | |
Merge branch 'of-offline-migration': offline daily view, remove scrapers
Diffstat (limited to 'internal/readings/offline.go')
| -rw-r--r-- | internal/readings/offline.go | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/internal/readings/offline.go b/internal/readings/offline.go new file mode 100644 index 0000000..566fc7a --- /dev/null +++ b/internal/readings/offline.go @@ -0,0 +1,140 @@ +package readings + +import ( + "fmt" + "time" + + "github.com/lukaszkasprzak/lectio/internal/bible" + "github.com/lukaszkasprzak/lectio/internal/caldata" + "github.com/lukaszkasprzak/lectio/internal/calendar" + "github.com/lukaszkasprzak/lectio/internal/config" + "github.com/lukaszkasprzak/lectio/internal/liturgy" +) + +// offlineLoad resolves a day's readings entirely from the embedded calendar +// engine and lectionary data -- no network. It returns the same source-agnostic +// liturgy.Section / liturgy.DayInfo the CLI/TUI/web already render, so the daily +// view is unchanged apart from where its data comes from. Citations are +// lectio's English-canonical authored form; the render localises each one to +// the chosen corpus's Psalter and the user's sigla dialect (see +// render.GatherVersion, bible.OFRef). +func offlineLoad(cfg config.Config, date string) ([]liturgy.Section, liturgy.DayInfo, error) { + d, err := time.Parse("2006-01-02", date) + if err != nil { + return nil, liturgy.DayInfo{}, fmt.Errorf("bad date %q (want YYYY-MM-DD)", date) + } + sel := cfg.Selection() + dir, _ := config.CalendarsDir() + layers, _ := caldata.Stack(sel.Form, dir, cfg.Use) // Stack falls back to embedded data on error + day := calendar.Compute(d.UTC(), sel, layers) + rs := caldata.Readings(sel, layers, d.UTC(), day) + tbl, _ := bible.LoadBookTable(config.UserBooksINI()) // nil on error -> citations shown as authored + return sectionsFor(rs, sel.Form, cfg.UILanguage, cfg.SiglaLang(), tbl), dayInfo(cfg, day), nil +} + +// citationForms renders a reading's authored (English) citation into its +// display form (the reader's sigla dialect) and its English-canonical lookup +// reference. When the book table is missing or cannot parse the citation, the +// authored form is used verbatim for both. +func citationForms(raw, siglaLang string, tbl *bible.BookTable) (display, ref string) { + if tbl == nil { + return raw, raw + } + canonical, ok := tbl.ParseRef("en", raw) + if !ok { + return raw, raw + } + return tbl.FormatRef(siglaLang, canonical), canonical +} + +// ofPart maps a computed reading Part to the modern-lectionary section id and +// its Polish heading label. The heading is always the Polish label: the render +// (render.LocalizeHeading) rewrites it to English for an English UI, mirroring +// how the niedziela sections were shaped. +var ofPart = map[string]struct{ id, heading string }{ + "first": {"pierwsze_czytanie", "1. czytanie"}, + "psalm": {"psalm", "Psalm"}, + "second": {"drugie_czytanie", "2. czytanie"}, + "acclamation": {"aklamacja", "Aklamacja"}, + "gospel": {"ewangelia", "Ewangelia"}, +} + +// efPartHeading gives the traditional (1962) section's heading per UI language; +// the EF has only an epistle/lesson and a gospel. Unlike the OF headings these +// are not translated downstream, so they are set in the target language here. +func efPartHeading(part, lang string) (id, heading string) { + pl := lang == "pl" + switch part { + case "first": + if pl { + return "epistola", "Lekcja" + } + return "epistola", "Lesson" + case "gospel": + if pl { + return "evangelium", "Ewangelia" + } + return "evangelium", "Gospel" + } + return "", "" +} + +// sectionsFor turns computed readings into render-ready sections, tagging each +// with the section id and heading its form expects and rendering its citation +// into display (sigla dialect) and lookup (English-canonical) forms. +func sectionsFor(rs []calendar.Reading, form, lang, siglaLang string, tbl *bible.BookTable) []liturgy.Section { + var out []liturgy.Section + for _, r := range rs { + if r.Citation == "" { + continue + } + var id, heading string + if form == "old" { + id, heading = efPartHeading(r.Part, lang) + } else if p, ok := ofPart[r.Part]; ok { + id, heading = p.id, p.heading + } + if id == "" { + continue // an unknown part carries no section + } + display, ref := citationForms(r.Citation, siglaLang, tbl) + out = append(out, liturgy.Section{ + PartID: id, + Heading: heading, + Citation: display, + Ref: ref, + }) + } + return out +} + +// dayInfo builds the header (celebration name, liturgical colour) for the +// computed day. Season is left empty: the celebration name already carries the +// temporal identity for temporal days, and the header is a nice-to-have. +func dayInfo(cfg config.Config, day calendar.LiturgicalDay) liturgy.DayInfo { + return liturgy.DayInfo{ + Name: celebrationName(cfg, day.Observed), + Colour: string(day.Colour), + } +} + +// celebrationName is the observed celebration's name in the UI language, +// falling back to English then a humanized slug for temporal days that carry no +// proper name (mirrors the CLI's cli.celebrationName). An empty result omits +// the header line. +func celebrationName(cfg config.Config, c calendar.Celebration) string { + lang := "en" + if cfg.UILanguage == "pl" { + lang = "pl" + } + if n := c.Name[lang]; n != "" { + return n + } + if n := c.Name["en"]; n != "" { + return n + } + if c.Slug == "" { + return "" + } + return calendar.HumanizeSlug(c.Slug) +} |
