feat: add cc front matter
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// Command seed-book-intro seeds a book's front-matter (intro-segments such as
|
||||
// Dedication, Front Flap, Preface, Introduction, Disciplic Succession) into the
|
||||
// `prose_chapters` MongoDB collection (volume=0, type="intro-segment").
|
||||
//
|
||||
// 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):
|
||||
//
|
||||
// go run ./cmd/seed-book-intro --book cc
|
||||
// go run ./cmd/seed-book-intro --book bg --dir ../extractor/jsons/books/bg/intro
|
||||
//
|
||||
// It is idempotent: a book's existing intro-segments are removed before insert.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/prabhupadasays/spsays-bff/internal/config"
|
||||
"github.com/prabhupadasays/spsays-bff/internal/repository"
|
||||
)
|
||||
|
||||
type introSegment struct {
|
||||
Slug string `json:"slug"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Book string `json:"book"`
|
||||
Volume int `json:"volume"`
|
||||
Order int `json:"order"`
|
||||
Paragraphs []string `json:"paragraphs"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
book := flag.String("book", "", "book code (e.g. bg, cc) — required")
|
||||
dir := flag.String("dir", "", "directory of intro-segment JSON files "+
|
||||
"(default: ../extractor/jsons/books/<book>/intro)")
|
||||
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()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to load config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger, _ := zap.NewDevelopment()
|
||||
defer logger.Sync()
|
||||
sugar := logger.Sugar()
|
||||
|
||||
mongoDB, err := repository.NewMongoDB(cfg.MongoURI, cfg.MongoDB, logger)
|
||||
if err != nil {
|
||||
sugar.Fatalf("failed to connect to MongoDB: %v", err)
|
||||
}
|
||||
defer mongoDB.Close()
|
||||
|
||||
entries, err := os.ReadDir(segDir)
|
||||
if err != nil {
|
||||
sugar.Fatalf("failed to read dir %s: %v", segDir, err)
|
||||
}
|
||||
|
||||
var files []string
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() && filepath.Ext(e.Name()) == ".json" {
|
||||
files = append(files, e.Name())
|
||||
}
|
||||
}
|
||||
sort.Strings(files)
|
||||
|
||||
var segments []introSegment
|
||||
for _, name := range files {
|
||||
raw, err := os.ReadFile(filepath.Join(segDir, name))
|
||||
if err != nil {
|
||||
sugar.Fatalf("read %s: %v", name, err)
|
||||
}
|
||||
var seg introSegment
|
||||
if err := json.Unmarshal(raw, &seg); err != nil {
|
||||
sugar.Fatalf("parse %s: %v", name, err)
|
||||
}
|
||||
if seg.Book != *book || seg.Type != "intro-segment" {
|
||||
sugar.Warnf("skipping %s (book=%q type=%q)", name, seg.Book, seg.Type)
|
||||
continue
|
||||
}
|
||||
segments = append(segments, seg)
|
||||
}
|
||||
|
||||
if len(segments) == 0 {
|
||||
sugar.Fatalf("no %s intro-segments found in %s", *book, segDir)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
col := mongoDB.Collection("prose_chapters")
|
||||
|
||||
del, err := col.DeleteMany(ctx, map[string]any{
|
||||
"book": *book,
|
||||
"type": "intro-segment",
|
||||
})
|
||||
if err != nil {
|
||||
sugar.Fatalf("delete existing %s intro-segments: %v", *book, err)
|
||||
}
|
||||
sugar.Infof("removed %d existing %s intro-segment(s)", del.DeletedCount, *book)
|
||||
|
||||
docs := make([]any, 0, len(segments))
|
||||
for _, seg := range segments {
|
||||
// chapter is null for intro-segments (matches the ProseChapterDoc shape).
|
||||
docs = append(docs, map[string]any{
|
||||
"book": *book,
|
||||
"volume": 0,
|
||||
"chapter": nil,
|
||||
"title": seg.Title,
|
||||
"type": "intro-segment",
|
||||
"slug": seg.Slug,
|
||||
"order": seg.Order,
|
||||
"paragraphs": seg.Paragraphs,
|
||||
})
|
||||
sugar.Infof(" %s (order %d, %d paragraphs)", seg.Slug, seg.Order, len(seg.Paragraphs))
|
||||
}
|
||||
|
||||
res, err := col.InsertMany(ctx, docs)
|
||||
if err != nil {
|
||||
sugar.Fatalf("insert %s intro-segments: %v", *book, err)
|
||||
}
|
||||
sugar.Infof("inserted %d %s intro-segment(s)", len(res.InsertedIDs), *book)
|
||||
}
|
||||
Reference in New Issue
Block a user