summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/gen-deutero.py62
-rw-r--r--scripts/genlect.go58
2 files changed, 110 insertions, 10 deletions
diff --git a/scripts/gen-deutero.py b/scripts/gen-deutero.py
new file mode 100644
index 0000000..ace721e
--- /dev/null
+++ b/scripts/gen-deutero.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+# gen-deutero.py -- backfill the deuterocanonical Daniel and Esther additions
+# that the base drb (Douay-Rheims) corpus omits: Daniel 13 (Susanna) & 14 (Bel
+# and the Dragon), and the Greek additions to Esther (chapters 11-16). The base
+# corpus used Hebrew-canon chapter counts (Daniel 1-12, Esther 1-10) even though
+# the Douay-Rheims itself carries these chapters; the EF Lenten lectionary reads
+# them (e.g. Susanna on Saturday of the 3rd week of Lent), so they are required.
+#
+# Source: get.bible v2 "douayrheims" (public domain). Latin (vul) already has
+# them; the Polish Wujek source (biblia.info.pl) uses the truncated 12-chapter
+# Daniel, so wuj cannot be filled from the existing pipeline (Latin fallback
+# covers Polish).
+#
+# Usage (from repo root):
+# python3 scripts/gen-deutero.py # print the rows (inspect)
+# python3 scripts/gen-deutero.py --apply # append to drb.tsv if not present
+#
+# Row format matches the corpus: Book\tAbbrev\tBookNum\tChapter\tVerse\tText
+import json, sys, urllib.request
+
+DRB = "internal/bible/corpora/drb.tsv"
+# (canonical book name, abbrev, book-number, [chapters]) -- must match drb.tsv.
+TARGETS = [
+ ("Daniel", "Dan", 27, range(13, 15)), # 13 Susanna, 14 Bel & the Dragon
+ ("Esther", "Est", 17, range(11, 17)), # 11-16 Greek additions
+]
+
+def get(url):
+ req = urllib.request.Request(url, headers={"User-Agent": "curl/8.0"})
+ with urllib.request.urlopen(req, timeout=25) as r:
+ return json.load(r)
+
+def rows():
+ out = []
+ for name, abbr, nr, chapters in TARGETS:
+ for ch in chapters:
+ d = get(f"https://api.getbible.net/v2/douayrheims/{nr}/{ch}.json")
+ for v in d.get("verses", []):
+ text = " ".join(v["text"].split()) # collapse whitespace, no tabs/newlines
+ out.append(f"{name}\t{abbr}\t{nr}\t{ch}\t{v['verse']}\t{text}")
+ return out
+
+def main():
+ apply = "--apply" in sys.argv[1:]
+ new = rows()
+ if not apply:
+ for r in new:
+ print(r)
+ print(f"# {len(new)} rows (not written; pass --apply to append)", file=sys.stderr)
+ return
+ existing = open(DRB, encoding="utf-8").read()
+ if "\nDaniel\tDan\t27\t13\t" in existing:
+ print("drb.tsv already has Daniel 13 -- refusing to duplicate", file=sys.stderr)
+ sys.exit(1)
+ with open(DRB, "a", encoding="utf-8") as f:
+ if not existing.endswith("\n"):
+ f.write("\n")
+ f.write("\n".join(new) + "\n")
+ print(f"appended {len(new)} rows to {DRB}", file=sys.stderr)
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/genlect.go b/scripts/genlect.go
index eec21b6..85ff1c2 100644
--- a/scripts/genlect.go
+++ b/scripts/genlect.go
@@ -3,7 +3,9 @@
// genlect generates the EF temporal Sunday lectionary from missalemeum
// (Divinum Officium data), keyed by lectio's computed temporal-day slug.
// One-time; requires network. Run from the repo root:
-// go run scripts/genlect.go
+//
+// go run scripts/genlect.go
+//
// Writes internal/caldata/tridentine-lectionary.ini.
package main
@@ -23,6 +25,26 @@ import (
var citeRe = regexp.MustCompile(`\*([^*]+)\*`)
+// bookCommaRe strips a stray comma between the book name and the first
+// chapter ("4 Kings, 5:1-15" -> "4 Kings 5:1-15"), a missalemeum data glitch.
+// The [^:] guard means it only fires before any chapter:verse, so legitimate
+// multi-chapter commas ("Gen 1:1, 2:3") are left intact.
+var bookCommaRe = regexp.MustCompile(`^([^:]*?),\s+(\d+:)`)
+
+// chapDotRe rewrites a European-style "chapter. verse" separator to a colon
+// ("John 20. 19-31" -> "John 20:19-31"), another missalemeum data glitch. It is
+// applied only when the citation carries no colon at all, so disjoint verse
+// groups in a normal citation ("Ps 62:2. 3-4") are never touched.
+var chapDotRe = regexp.MustCompile(`(\d+)\.\s+(\d)`)
+
+func cleanCite(s string) string {
+ s = bookCommaRe.ReplaceAllString(strings.TrimSpace(s), "$1 $2")
+ if !strings.Contains(s, ":") {
+ s = chapDotRe.ReplaceAllString(s, "$1:$2")
+ }
+ return s
+}
+
func fetchCitations(date string) (epistle, gospel string) {
resp, err := http.Get("https://www.missalemeum.com/en/api/v5/proper/" + date)
if err != nil {
@@ -48,9 +70,9 @@ func fetchCitations(date string) (epistle, gospel string) {
}
switch s.ID {
case "Lectio":
- epistle = strings.TrimSpace(m[1])
+ epistle = cleanCite(m[1])
case "Evangelium":
- gospel = strings.TrimSpace(m[1])
+ gospel = cleanCite(m[1])
}
}
return
@@ -64,24 +86,40 @@ func main() {
start := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2028, 12, 31, 0, 0, 0, 0, time.UTC)
+ seen := map[string]bool{}
+ // Seasons whose weekdays may have PROPER Masses (else a ferial repeats the
+ // preceding Sunday and is resolved by the CLI fallback, so we skip it).
+ properFerial := map[calendar.Season]bool{
+ calendar.Advent: true, calendar.Lent: true,
+ calendar.Passiontide: true, calendar.Easter_: true,
+ }
for d := start; !d.After(end); d = d.AddDate(0, 0, 1) {
- if d.Weekday() != time.Sunday {
- continue
- }
day := calendar.Compute(d, sel, layers)
- if day.Observed.Layer != "temporal" { // a feast won that Sunday -> its own propers
+ if day.Observed.Layer != "temporal" { // a feast won -> its own propers
continue
}
slug := day.Observed.Slug
- if _, ok := lect[slug]; ok {
- continue // one instance per slug
+ isSunday := d.Weekday() == time.Sunday
+ if !isSunday && !properFerial[day.Season] {
+ continue // green-season feria -> repeats the Sunday
+ }
+ if seen[slug] {
+ continue
}
ep, gos := fetchCitations(d.Format("2006-01-02"))
if ep == "" && gos == "" {
continue
}
+ seen[slug] = true
+ if !isSunday {
+ // store only if the reading differs from the preceding Sunday's Mass
+ sun := d.AddDate(0, 0, -int(d.Weekday()))
+ if r, ok := lect[calendar.Compute(sun, sel, layers).Observed.Slug]; ok && r[0] == ep && r[1] == gos {
+ continue // a repeat -> the CLI fallback handles it
+ }
+ }
lect[slug] = [2]string{ep, gos}
- fmt.Fprintf(os.Stderr, "%s %-34s ep=%-22s go=%s\n", d.Format("2006-01-02"), slug, ep, gos)
+ fmt.Fprintf(os.Stderr, "%s %-38s ep=%-22s go=%s\n", d.Format("2006-01-02"), slug, ep, gos)
}
slugs := make([]string, 0, len(lect))