summaryrefslogtreecommitdiff
path: root/internal/liturgy/parse.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-24 10:32:28 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-24 10:32:28 +0200
commitc9f3bf46f0de09edb796e35f3dcff349febf75c9 (patch)
treec1a0b98b484e4da557c1ab205dfff0d92ce8ac36 /internal/liturgy/parse.go
parenta865374755480a4aef2a6156afccdf08a91422ea (diff)
downloadlectio-c9f3bf46f0de09edb796e35f3dcff349febf75c9.tar.gz
lectio-c9f3bf46f0de09edb796e35f3dcff349febf75c9.zip
dayinfo: show feast/day name + colour (modern niedziela + traditional missalemeum) in cli/tui/web; v0.5.0
Diffstat (limited to 'internal/liturgy/parse.go')
-rw-r--r--internal/liturgy/parse.go53
1 files changed, 53 insertions, 0 deletions
diff --git a/internal/liturgy/parse.go b/internal/liturgy/parse.go
index 64e6928..4c1a935 100644
--- a/internal/liturgy/parse.go
+++ b/internal/liturgy/parse.go
@@ -23,8 +23,32 @@ var (
h4Re = regexp.MustCompile(`(?s)<h4>(.*?)</h4>`)
pRe = regexp.MustCompile(`(?s)<p>(.*?)</p>`)
citationRe = regexp.MustCompile(`\((.+)\)\s*$`)
+
+ // dayNamePRe matches every classed <p><em>...</em></p> on the page; only
+ // the one whose class carries both "fw-bold" and a "color-" role (see
+ // dayNameParaMatches) is the day's celebration name -- the page also
+ // carries a plain fw-bold (no color-) lookalike higher up that must not
+ // win instead.
+ dayNamePRe = regexp.MustCompile(`(?s)<p class="([^"]*)">\s*<em>(.*?)</em>\s*</p>`)
+
+ // dayColourRe matches niedziela.pl's "Kolor szat: <word>" vestment-colour
+ // line, tolerating the <span>/<strong> markup wrapped around the colour
+ // word on the page (see internal/liturgy/testdata/2026-07-22.html).
+ dayColourRe = regexp.MustCompile(`Kolor szat:\s*(?:<[^>]+>\s*)*([\p{L}]+)`)
)
+// modernColours maps niedziela.pl's Polish vestment-colour words to
+// DayInfo's normalized colour names; anything not listed here (including a
+// multi-option line like "zielony albo biały albo czerwony", which matches
+// only its first word) is left for the caller to treat as "" if absent.
+var modernColours = map[string]string{
+ "biały": "white",
+ "zielony": "green",
+ "fioletowy": "violet",
+ "czerwony": "red",
+ "różowy": "rose",
+}
+
// panePattern matches the opening tag of the tab-pane div carrying the given
// tab id, e.g. `<div class="tab-pane fade " id="tabnowy0all">`.
func panePattern(tab string) *regexp.Regexp {
@@ -122,6 +146,35 @@ func Parse(pageHTML string) ([]Section, error) {
return sections, nil
}
+// ParseDayInfo extracts the day's celebration name and liturgical colour
+// from a niedziela.pl page: Name is the inner text of the <p class="...
+// fw-bold color-XXX"><em>NAME</em></p> paragraph (there is also an earlier,
+// plain fw-bold-but-no-color- lookalike on the page -- see dayNamePRe --
+// which must not match instead), and Colour comes from the page's "Kolor
+// szat: <word>" line, mapped via modernColours (case-insensitive; unknown
+// word -> ""). Season is always "" -- the modern lectionary folds its
+// temporal context into Name on temporal days rather than carrying it
+// separately. A page whose markup doesn't match either pattern (a layout
+// change, or a fixture with neither) yields a zero DayInfo, never an error:
+// the readings are the load-bearing content, the header is a nice-to-have.
+func ParseDayInfo(pageHTML string) DayInfo {
+ var info DayInfo
+
+ for _, m := range dayNamePRe.FindAllStringSubmatch(pageHTML, -1) {
+ class := m[1]
+ if strings.Contains(class, "fw-bold") && strings.Contains(class, "color-") {
+ info.Name = strings.Join(htmlToLines(m[2]), " ")
+ break
+ }
+ }
+
+ if m := dayColourRe.FindStringSubmatch(pageHTML); m != nil {
+ info.Colour = modernColours[strings.ToLower(m[1])]
+ }
+
+ return info
+}
+
// partID assigns the stable liturgical-part identifier for a section heading.
// A second "1. czytanie" heading on the same day (a split feast offering two
// alternative first readings) becomes "drugie_czytanie" instead of colliding