feat: add cc front matter
This commit is contained in:
@@ -1,15 +1,16 @@
|
|||||||
// Command seed-bg-intro seeds the Bhagavad-gītā front-matter (Dedication,
|
// Command seed-book-intro seeds a book's front-matter (intro-segments such as
|
||||||
// Foreword, Preface, Introduction, The Disciplic Succession) into the
|
// Dedication, Front Flap, Preface, Introduction, Disciplic Succession) into the
|
||||||
// `prose_chapters` MongoDB collection as intro-segments (book="bg", volume=0).
|
// `prose_chapters` MongoDB collection (volume=0, type="intro-segment").
|
||||||
//
|
//
|
||||||
// The segment JSON is produced by extractor/scripts/bg_intro_extract.py.
|
// The segment JSON is produced by the per-book extractor scripts, e.g.
|
||||||
|
// extractor/scripts/bg_intro_extract.py, cc_intro_extract.py.
|
||||||
//
|
//
|
||||||
// Usage (from the spsays-bff directory, so .env is picked up):
|
// Usage (from the spsays-bff directory, so .env is picked up):
|
||||||
//
|
//
|
||||||
// go run ./cmd/seed-bg-intro
|
// go run ./cmd/seed-book-intro --book cc
|
||||||
// go run ./cmd/seed-bg-intro --dir ../extractor/jsons/books/bg/intro
|
// go run ./cmd/seed-book-intro --book bg --dir ../extractor/jsons/books/bg/intro
|
||||||
//
|
//
|
||||||
// It is idempotent: existing bg intro-segments are removed before insert.
|
// It is idempotent: a book's existing intro-segments are removed before insert.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -39,10 +40,20 @@ type introSegment struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
dir := flag.String("dir", "../extractor/jsons/books/bg/intro",
|
book := flag.String("book", "", "book code (e.g. bg, cc) — required")
|
||||||
"directory containing bg intro-segment JSON files")
|
dir := flag.String("dir", "", "directory of intro-segment JSON files "+
|
||||||
|
"(default: ../extractor/jsons/books/<book>/intro)")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if *book == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "--book is required")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
segDir := *dir
|
||||||
|
if segDir == "" {
|
||||||
|
segDir = filepath.Join("..", "extractor", "jsons", "books", *book, "intro")
|
||||||
|
}
|
||||||
|
|
||||||
cfg, err := config.Load()
|
cfg, err := config.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "failed to load config: %v\n", err)
|
fmt.Fprintf(os.Stderr, "failed to load config: %v\n", err)
|
||||||
@@ -59,23 +70,22 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer mongoDB.Close()
|
defer mongoDB.Close()
|
||||||
|
|
||||||
entries, err := os.ReadDir(*dir)
|
entries, err := os.ReadDir(segDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sugar.Fatalf("failed to read dir %s: %v", *dir, err)
|
sugar.Fatalf("failed to read dir %s: %v", segDir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var segments []introSegment
|
|
||||||
var files []string
|
var files []string
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
if e.IsDir() || filepath.Ext(e.Name()) != ".json" {
|
if !e.IsDir() && filepath.Ext(e.Name()) == ".json" {
|
||||||
continue
|
files = append(files, e.Name())
|
||||||
}
|
}
|
||||||
files = append(files, e.Name())
|
|
||||||
}
|
}
|
||||||
sort.Strings(files)
|
sort.Strings(files)
|
||||||
|
|
||||||
|
var segments []introSegment
|
||||||
for _, name := range files {
|
for _, name := range files {
|
||||||
raw, err := os.ReadFile(filepath.Join(*dir, name))
|
raw, err := os.ReadFile(filepath.Join(segDir, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sugar.Fatalf("read %s: %v", name, err)
|
sugar.Fatalf("read %s: %v", name, err)
|
||||||
}
|
}
|
||||||
@@ -83,7 +93,7 @@ func main() {
|
|||||||
if err := json.Unmarshal(raw, &seg); err != nil {
|
if err := json.Unmarshal(raw, &seg); err != nil {
|
||||||
sugar.Fatalf("parse %s: %v", name, err)
|
sugar.Fatalf("parse %s: %v", name, err)
|
||||||
}
|
}
|
||||||
if seg.Book != "bg" || seg.Type != "intro-segment" {
|
if seg.Book != *book || seg.Type != "intro-segment" {
|
||||||
sugar.Warnf("skipping %s (book=%q type=%q)", name, seg.Book, seg.Type)
|
sugar.Warnf("skipping %s (book=%q type=%q)", name, seg.Book, seg.Type)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -91,7 +101,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(segments) == 0 {
|
if len(segments) == 0 {
|
||||||
sugar.Fatal("no bg intro-segments found to seed")
|
sugar.Fatalf("no %s intro-segments found in %s", *book, segDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
@@ -99,22 +109,20 @@ func main() {
|
|||||||
|
|
||||||
col := mongoDB.Collection("prose_chapters")
|
col := mongoDB.Collection("prose_chapters")
|
||||||
|
|
||||||
// Idempotent: clear any previously seeded bg intro-segments.
|
|
||||||
del, err := col.DeleteMany(ctx, map[string]any{
|
del, err := col.DeleteMany(ctx, map[string]any{
|
||||||
"book": "bg",
|
"book": *book,
|
||||||
"type": "intro-segment",
|
"type": "intro-segment",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sugar.Fatalf("delete existing bg intro-segments: %v", err)
|
sugar.Fatalf("delete existing %s intro-segments: %v", *book, err)
|
||||||
}
|
}
|
||||||
sugar.Infof("removed %d existing bg intro-segment(s)", del.DeletedCount)
|
sugar.Infof("removed %d existing %s intro-segment(s)", del.DeletedCount, *book)
|
||||||
|
|
||||||
docs := make([]any, 0, len(segments))
|
docs := make([]any, 0, len(segments))
|
||||||
for _, seg := range segments {
|
for _, seg := range segments {
|
||||||
// chapter is intentionally null for intro-segments (matches the
|
// chapter is null for intro-segments (matches the ProseChapterDoc shape).
|
||||||
// ProseChapterDoc shape used by KB/NoD front matter).
|
|
||||||
docs = append(docs, map[string]any{
|
docs = append(docs, map[string]any{
|
||||||
"book": "bg",
|
"book": *book,
|
||||||
"volume": 0,
|
"volume": 0,
|
||||||
"chapter": nil,
|
"chapter": nil,
|
||||||
"title": seg.Title,
|
"title": seg.Title,
|
||||||
@@ -128,7 +136,7 @@ func main() {
|
|||||||
|
|
||||||
res, err := col.InsertMany(ctx, docs)
|
res, err := col.InsertMany(ctx, docs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sugar.Fatalf("insert bg intro-segments: %v", err)
|
sugar.Fatalf("insert %s intro-segments: %v", *book, err)
|
||||||
}
|
}
|
||||||
sugar.Infof("inserted %d bg intro-segment(s)", len(res.InsertedIDs))
|
sugar.Infof("inserted %d %s intro-segment(s)", len(res.InsertedIDs), *book)
|
||||||
}
|
}
|
||||||
@@ -421,10 +421,13 @@ func (s *Server) setupRouter() {
|
|||||||
r.Get("/{division}/{chapter}/{verse}", s.bookH.GetDivisionVerse)
|
r.Get("/{division}/{chapter}/{verse}", s.bookH.GetDivisionVerse)
|
||||||
})
|
})
|
||||||
|
|
||||||
// CC — līlā divisions
|
// CC — līlā divisions (plus prose front-matter segments;
|
||||||
|
// the static /chapters routes take precedence over /{division}).
|
||||||
r.Route("/cc", func(r chi.Router) {
|
r.Route("/cc", func(r chi.Router) {
|
||||||
r.Use(injectBookCode("cc"))
|
r.Use(injectBookCode("cc"))
|
||||||
r.Get("/", s.bookH.GetBook)
|
r.Get("/", s.bookH.GetBook)
|
||||||
|
r.Get("/chapters", s.bookH.ListProseChapters)
|
||||||
|
r.Get("/chapters/{slug}", s.bookH.GetProseChapter)
|
||||||
r.Get("/{division}", s.bookH.GetDivisionInfo)
|
r.Get("/{division}", s.bookH.GetDivisionInfo)
|
||||||
r.Get("/{division}/{chapter}", s.bookH.GetDivisionChapterVerseIndex)
|
r.Get("/{division}/{chapter}", s.bookH.GetDivisionChapterVerseIndex)
|
||||||
r.Get("/{division}/{chapter}/verses", s.bookH.GetDivisionChapterVerses)
|
r.Get("/{division}/{chapter}/verses", s.bookH.GetDivisionChapterVerses)
|
||||||
|
|||||||
Reference in New Issue
Block a user