689 lines
23 KiB
Python
689 lines
23 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract The Jaladuta Diary (1965) from others-before-1977.html.
|
|
|
|
Each diary day entry becomes its own chapter file.
|
|
Chapters are grouped by month in the intro.json metadata.
|
|
|
|
Structure:
|
|
- Preface and Introduction are standalone chapters (slugs "preface", "introduction")
|
|
- Day entries use slugs like "apr-3", "may-2", "aug-13", "sep-1", etc.
|
|
- The "Memoranda" entry at the end uses slug "memoranda"
|
|
- Months are parent groups in intro.json (non-clickable headings)
|
|
|
|
Output:
|
|
lib/jsons/journals/jaladuta-diary/intro.json
|
|
lib/jsons/journals/jaladuta-diary/chapters/preface.json
|
|
lib/jsons/journals/jaladuta-diary/chapters/introduction.json
|
|
lib/jsons/journals/jaladuta-diary/chapters/apr-3.json
|
|
lib/jsons/journals/jaladuta-diary/chapters/apr-5.json
|
|
...
|
|
lib/jsons/journals/jaladuta-diary/chapters/nov-28.json
|
|
lib/jsons/journals/jaladuta-diary/chapters/memoranda.json
|
|
|
|
Usage:
|
|
python3 scripts/jaladuta_diary_extract.py
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from bs4 import BeautifulSoup, Tag
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ScaGoudy → IAST Unicode mapping
|
|
# ---------------------------------------------------------------------------
|
|
SCAGOUDY_TO_IAST = {
|
|
"ä": "ā",
|
|
"Ä": "Ā",
|
|
"å": "ṛ",
|
|
"Å": "Ṛ",
|
|
"ñ": "ṣ",
|
|
"Ñ": "Ṣ",
|
|
"ö": "ṭ",
|
|
"Ö": "Ṭ",
|
|
"ë": "ṇ",
|
|
"Ë": "Ṇ",
|
|
"ò": "ḍ",
|
|
"Ò": "Ḍ",
|
|
"ç": "ś",
|
|
"Ç": "Ś",
|
|
"ì": "ṅ",
|
|
"Ì": "Ṅ",
|
|
"ï": "ñ",
|
|
"Ï": "Ñ",
|
|
"ü": "ū",
|
|
"Ü": "Ū",
|
|
"é": "ī",
|
|
"É": "Ī",
|
|
"à": "ṁ",
|
|
"ù": "ḥ",
|
|
"è": "ṝ",
|
|
"ÿ": "ḷ",
|
|
}
|
|
|
|
|
|
def decode_scagoudy(text: str) -> str:
|
|
"""Replace ScaGoudy-encoded characters with proper IAST Unicode."""
|
|
for src, dst in SCAGOUDY_TO_IAST.items():
|
|
text = text.replace(src, dst)
|
|
return text
|
|
|
|
|
|
def get_css_class(tag: Tag) -> str:
|
|
classes = tag.get("class", [])
|
|
return classes[0] if classes else ""
|
|
|
|
|
|
def inner_html(tag: Tag) -> str:
|
|
"""Get inner HTML of a tag, decode ScaGoudy, clean up spans."""
|
|
html = "".join(str(child) for child in tag.children)
|
|
html = decode_scagoudy(html)
|
|
# <span class="s3">text</span> → <i>text</i>
|
|
html = re.sub(
|
|
r'<span[^>]*class="s3"[^>]*>(.*?)</span>', r"<i>\1</i>", html, flags=re.DOTALL
|
|
)
|
|
# <span class="s5">...</span> → keep inner text
|
|
html = re.sub(
|
|
r'<span[^>]*class="s5"[^>]*>(.*?)</span>', r"\1", html, flags=re.DOTALL
|
|
)
|
|
# <span class="s13">...</span> → keep inner text
|
|
html = re.sub(
|
|
r'<span[^>]*class="s1[0-9]+"[^>]*>(.*?)</span>', r"\1", html, flags=re.DOTALL
|
|
)
|
|
# <span class="s23">...</span> → keep inner text
|
|
html = re.sub(
|
|
r'<span[^>]*class="s2[0-9]+"[^>]*>(.*?)</span>', r"\1", html, flags=re.DOTALL
|
|
)
|
|
# Remove any remaining spans but keep content
|
|
html = re.sub(r"<span[^>]*>(.*?)</span>", r"\1", html, flags=re.DOTALL)
|
|
# Clean up Apple-tab-span leftovers
|
|
html = html.replace('<span class="Apple-tab-span">\t</span>', "\t")
|
|
# Collapse multiple spaces (but not around <br>)
|
|
html = re.sub(r"[ \t]+", " ", html)
|
|
html = html.strip()
|
|
# Remove leading <br> tags
|
|
html = re.sub(r"^(<br\s*/?>[\s]*)+", "", html)
|
|
return html
|
|
|
|
|
|
def write_json(data: dict, path: str):
|
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Month abbreviation helpers
|
|
# ---------------------------------------------------------------------------
|
|
MONTH_ABBR = {
|
|
"april": "apr",
|
|
"may": "may",
|
|
"june": "jun",
|
|
"july": "jul",
|
|
"august": "aug",
|
|
"september": "sep",
|
|
"october": "oct",
|
|
"november": "nov",
|
|
}
|
|
|
|
MONTH_ORDER = ["apr", "may", "jun", "jul", "aug", "sep", "oct", "nov"]
|
|
|
|
DAY_NAMES = {
|
|
"monday",
|
|
"tuesday",
|
|
"wednesday",
|
|
"thursday",
|
|
"friday",
|
|
"saturday",
|
|
"sunday",
|
|
}
|
|
|
|
|
|
def parse_day_header(bold_text: str):
|
|
"""Parse the bold header of a diary entry to extract day name and date number.
|
|
|
|
Handles formats like:
|
|
"SATURDAY 3"
|
|
"13 FRIDAY"
|
|
"SATURDAY" (date-less, like Aug 14)
|
|
"MEMORANDA"
|
|
Returns (day_name, date_number) or (None, None) if not a day entry.
|
|
"""
|
|
text = bold_text.strip().split("\n")[0].strip()
|
|
text = re.sub(r"<br\s*/?>", " ", text).strip()
|
|
|
|
if text.upper() == "MEMORANDA":
|
|
return ("MEMORANDA", None)
|
|
|
|
# Try "DAY NUMBER" pattern
|
|
m = re.match(r"([A-Za-z]+)\s+(\d+)", text)
|
|
if m:
|
|
day = m.group(1).upper()
|
|
num = int(m.group(2))
|
|
if day in {d.upper() for d in DAY_NAMES}:
|
|
return (day, num)
|
|
|
|
# Try "NUMBER DAY" pattern
|
|
m = re.match(r"(\d+)\s+([A-Za-z]+)", text)
|
|
if m:
|
|
num = int(m.group(1))
|
|
day = m.group(2).upper()
|
|
if day in {d.upper() for d in DAY_NAMES}:
|
|
return (day, num)
|
|
|
|
# Try just "DAY" (no number — like SATURDAY 14 where 14 is on next line)
|
|
word = text.split()[0].upper() if text.split() else ""
|
|
if word in {d.upper() for d in DAY_NAMES}:
|
|
# Try to find number after
|
|
rest = text[len(word) :].strip()
|
|
m2 = re.match(r"(\d+)", rest)
|
|
if m2:
|
|
return (word, int(m2.group(1)))
|
|
return (word, None)
|
|
|
|
return (None, None)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main extraction
|
|
# ---------------------------------------------------------------------------
|
|
def main():
|
|
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
html_path = os.path.join(base_dir, "public", "html", "others-before-1977.html")
|
|
output_dir = os.path.join(base_dir, "lib", "jsons", "journals", "jaladuta-diary")
|
|
chapters_dir = os.path.join(output_dir, "chapters")
|
|
|
|
if not os.path.exists(html_path):
|
|
print(f"ERROR: {html_path} not found!")
|
|
sys.exit(1)
|
|
|
|
print(f"Reading {html_path}...")
|
|
with open(html_path, "r", encoding="utf-8") as f:
|
|
content = f.read()
|
|
|
|
soup = BeautifulSoup(content, "html.parser")
|
|
all_tags = soup.find_all("p")
|
|
print(f" Parsed {len(all_tags)} <p> tags total")
|
|
|
|
# Find the Jaladuta Diary section boundaries
|
|
start_idx = None
|
|
end_idx = None
|
|
for i, tag in enumerate(all_tags):
|
|
text = tag.get_text().strip()
|
|
cls = get_css_class(tag)
|
|
if cls == "p35" and "Jaladuta Diary" in text:
|
|
start_idx = i
|
|
if start_idx is not None and i > start_idx:
|
|
# End at "Prayers Written by Śrīla Prabhupāda aboard the Jaladuta" or the next p4 bookmark after JD
|
|
if cls == "p4" and "JD 8" in text:
|
|
end_idx = i
|
|
break
|
|
|
|
if start_idx is None:
|
|
print("ERROR: Could not find Jaladuta Diary start")
|
|
sys.exit(1)
|
|
if end_idx is None:
|
|
# Fallback: use the memoranda end
|
|
for i, tag in enumerate(all_tags):
|
|
if (
|
|
i > start_idx
|
|
and "MEMORANDA" in tag.get_text()
|
|
and get_css_class(tag) == "p110"
|
|
):
|
|
end_idx = i + 1
|
|
break
|
|
|
|
print(f" Section: tags[{start_idx}] → tags[{end_idx}]")
|
|
|
|
section_tags = all_tags[start_idx:end_idx]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 1: Extract Preface and Introduction
|
|
# ---------------------------------------------------------------------------
|
|
preface_paragraphs = []
|
|
intro_paragraphs = []
|
|
current_section = None # "preface" | "introduction" | None
|
|
|
|
# Also track where months/diary entries begin
|
|
diary_start_idx = None
|
|
|
|
for i, tag in enumerate(section_tags):
|
|
cls = get_css_class(tag)
|
|
text = tag.get_text().strip()
|
|
|
|
# Detect Preface header
|
|
if cls == "p3" and text == "Preface":
|
|
current_section = "preface"
|
|
continue
|
|
if cls == "p153": # bookmark
|
|
continue
|
|
|
|
# Detect Introduction header
|
|
if cls in ("p11", "p157") and "Introduction" in text:
|
|
if cls == "p157":
|
|
current_section = "introduction"
|
|
continue
|
|
elif cls == "p11":
|
|
current_section = "introduction"
|
|
continue
|
|
|
|
# Detect month start (diary entries begin)
|
|
if cls == "p11" and re.match(r"JD \d+:", text):
|
|
diary_start_idx = i
|
|
current_section = None
|
|
break
|
|
|
|
if cls == "p29":
|
|
# Bold month header like "APRIL 1965" — this is diary territory
|
|
diary_start_idx = i
|
|
current_section = None
|
|
break
|
|
|
|
# Collect preface/intro paragraphs
|
|
if current_section == "preface" and cls in ("p154", "p155", "p156"):
|
|
html = inner_html(tag)
|
|
if html:
|
|
preface_paragraphs.append(html)
|
|
elif current_section == "introduction" and cls in ("p154", "p155", "p156"):
|
|
html = inner_html(tag)
|
|
if html:
|
|
intro_paragraphs.append(html)
|
|
|
|
print(f"\n Preface: {len(preface_paragraphs)} paragraphs")
|
|
print(f" Introduction: {len(intro_paragraphs)} paragraphs")
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 2: Extract diary entries grouped by month
|
|
# ---------------------------------------------------------------------------
|
|
# Walk through remaining tags, tracking current month
|
|
|
|
current_month = None # "apr", "may", etc.
|
|
current_month_full = None # "April 1965", etc.
|
|
|
|
# Section headers that appear mid-month
|
|
section_headers = {} # Maps tag index to header text
|
|
|
|
# All day entries: list of { month, day, date, slug, title, paragraphs }
|
|
day_entries = []
|
|
current_entry = None
|
|
|
|
MONTH_MAP = {
|
|
"APRIL": ("apr", "April 1965"),
|
|
"MAY": ("may", "May 1965"),
|
|
"JUNE": ("jun", "June 1965"),
|
|
"JULY": ("jul", "July 1965"),
|
|
"AUGUST": ("aug", "August 1965"),
|
|
"SEPTEMBER": ("sep", "September 1965"),
|
|
"OCTOBER": ("oct", "October 1965"),
|
|
"NOVEMBER": ("nov", "November 1965"),
|
|
}
|
|
|
|
def finalize_entry():
|
|
nonlocal current_entry
|
|
if current_entry and current_entry["paragraphs"]:
|
|
day_entries.append(current_entry)
|
|
current_entry = None
|
|
|
|
diary_tags = section_tags[diary_start_idx:] if diary_start_idx else []
|
|
|
|
for i, tag in enumerate(diary_tags):
|
|
cls = get_css_class(tag)
|
|
text = tag.get_text().strip()
|
|
|
|
# Skip bookmarks
|
|
if cls in ("p11", "p4", "p39", "p153"):
|
|
continue
|
|
|
|
# Detect month headers (p29 bold)
|
|
if cls == "p29":
|
|
html = inner_html(tag)
|
|
# Check if this is a month header like "APRIL 1965" or "MAY 1965"
|
|
for month_key, (abbr, full) in MONTH_MAP.items():
|
|
if month_key in text.upper():
|
|
finalize_entry()
|
|
current_month = abbr
|
|
current_month_full = full
|
|
break
|
|
else:
|
|
# Could be a section header like "Verse 1." — skip if not month
|
|
# Or it could be a section header within a month
|
|
pass
|
|
continue
|
|
|
|
# Detect section headers (p68 class — "The Journey", "America")
|
|
if cls == "p68":
|
|
finalize_entry()
|
|
html = inner_html(tag)
|
|
# Create a section-header entry
|
|
if html and current_month:
|
|
section_entry = {
|
|
"month": current_month,
|
|
"month_full": current_month_full,
|
|
"day": None,
|
|
"date": None,
|
|
"slug": None,
|
|
"title": None,
|
|
"paragraphs": [f"<b>{re.sub('<[^>]+>', ' ', html).strip()}</b>"],
|
|
"is_section_header": True,
|
|
}
|
|
# Extract title text
|
|
plain = re.sub("<[^>]+>", " ", html)
|
|
plain = re.sub(r"\s+", " ", plain).strip()
|
|
section_entry["title"] = plain
|
|
day_entries.append(section_entry)
|
|
continue
|
|
|
|
# Detect diary entries (p110 class)
|
|
if cls == "p110":
|
|
finalize_entry()
|
|
|
|
html = inner_html(tag)
|
|
if not html:
|
|
continue
|
|
|
|
# Parse the bold header
|
|
b_tag = tag.find("b")
|
|
if b_tag:
|
|
bold_text = b_tag.get_text().strip()
|
|
day_name, date_num = parse_day_header(bold_text)
|
|
else:
|
|
day_name, date_num = (None, None)
|
|
|
|
if day_name == "MEMORANDA":
|
|
current_entry = {
|
|
"month": current_month,
|
|
"month_full": current_month_full,
|
|
"day": "MEMORANDA",
|
|
"date": None,
|
|
"slug": "memoranda",
|
|
"title": "Memoranda",
|
|
"paragraphs": [html],
|
|
"is_section_header": False,
|
|
}
|
|
elif day_name and date_num and current_month:
|
|
slug = f"{current_month}-{date_num}"
|
|
title = f"{day_name.capitalize()} {date_num}"
|
|
current_entry = {
|
|
"month": current_month,
|
|
"month_full": current_month_full,
|
|
"day": day_name,
|
|
"date": date_num,
|
|
"slug": slug,
|
|
"title": title,
|
|
"paragraphs": [html],
|
|
"is_section_header": False,
|
|
}
|
|
elif day_name and current_month:
|
|
# Day without date number (rare — like "SATURDAY" alone on Aug 14)
|
|
# Try to infer from context or just skip
|
|
slug = f"{current_month}-{day_name.lower()}"
|
|
title = day_name.capitalize()
|
|
current_entry = {
|
|
"month": current_month,
|
|
"month_full": current_month_full,
|
|
"day": day_name,
|
|
"date": None,
|
|
"slug": slug,
|
|
"title": title,
|
|
"paragraphs": [html],
|
|
"is_section_header": False,
|
|
}
|
|
else:
|
|
# Can't parse — treat as continuation or standalone
|
|
current_entry = {
|
|
"month": current_month,
|
|
"month_full": current_month_full,
|
|
"day": None,
|
|
"date": None,
|
|
"slug": None,
|
|
"title": text[:50],
|
|
"paragraphs": [html],
|
|
"is_section_header": False,
|
|
}
|
|
continue
|
|
|
|
# Detect p12 paragraphs (continuation text in some entries like Sep 16)
|
|
if cls == "p12" and current_entry:
|
|
html = inner_html(tag)
|
|
if html:
|
|
current_entry["paragraphs"].append(html)
|
|
continue
|
|
|
|
# p155 (source citations within diary section)
|
|
if cls == "p155" and current_entry:
|
|
html = inner_html(tag)
|
|
if html:
|
|
current_entry["paragraphs"].append(html)
|
|
continue
|
|
|
|
finalize_entry()
|
|
|
|
print(f"\n Total day entries extracted: {len(day_entries)}")
|
|
|
|
# Count by month
|
|
month_counts = {}
|
|
for entry in day_entries:
|
|
m = entry["month"]
|
|
month_counts[m] = month_counts.get(m, 0) + 1
|
|
for m in MONTH_ORDER:
|
|
if m in month_counts:
|
|
print(f" {m}: {month_counts[m]} entries")
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 3: Fix up entries — handle dateless entries, dedup slugs
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Some entries have no date — try to fix known cases
|
|
# Aug "SATURDAY" without number is Aug 14 (follows Aug 13 FRIDAY)
|
|
for i, entry in enumerate(day_entries):
|
|
if entry.get("is_section_header"):
|
|
continue
|
|
if entry["date"] is None and entry["day"] and entry["day"] != "MEMORANDA":
|
|
# Try to infer from previous entry
|
|
if i > 0:
|
|
prev = day_entries[i - 1]
|
|
if prev["date"] and prev["month"] == entry["month"]:
|
|
inferred = prev["date"] + 1
|
|
entry["date"] = inferred
|
|
entry["slug"] = f"{entry['month']}-{inferred}"
|
|
entry["title"] = f"{entry['day'].capitalize()} {inferred}"
|
|
print(
|
|
f" Inferred date: {entry['slug']} (from previous {prev['slug']})"
|
|
)
|
|
|
|
# Ensure unique slugs
|
|
seen_slugs = set()
|
|
for entry in day_entries:
|
|
if entry.get("is_section_header"):
|
|
continue
|
|
slug = entry["slug"]
|
|
if slug and slug in seen_slugs:
|
|
# Append suffix
|
|
suffix = 2
|
|
while f"{slug}-{suffix}" in seen_slugs:
|
|
suffix += 1
|
|
entry["slug"] = f"{slug}-{suffix}"
|
|
print(f" Deduped slug: {slug} → {entry['slug']}")
|
|
if slug:
|
|
seen_slugs.add(entry["slug"])
|
|
|
|
# Merge section headers into the next entry's paragraphs (prepend)
|
|
merged_entries = []
|
|
pending_header = None
|
|
for entry in day_entries:
|
|
if entry.get("is_section_header"):
|
|
pending_header = entry["paragraphs"][0]
|
|
continue
|
|
if pending_header:
|
|
entry["paragraphs"] = [pending_header] + entry["paragraphs"]
|
|
pending_header = None
|
|
merged_entries.append(entry)
|
|
day_entries = merged_entries
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 4: Build intro.json with hierarchical month groups
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Assign chapter numbers: preface=1, introduction=2, then day entries sequentially
|
|
chapter_num = 1
|
|
|
|
all_chapters = []
|
|
|
|
# Preface
|
|
preface_chapter = {
|
|
"slug": "preface",
|
|
"title": "Preface",
|
|
"number": chapter_num,
|
|
}
|
|
all_chapters.append(preface_chapter)
|
|
chapter_num += 1
|
|
|
|
# Introduction
|
|
intro_chapter = {
|
|
"slug": "introduction",
|
|
"title": "Introduction",
|
|
"number": chapter_num,
|
|
}
|
|
all_chapters.append(intro_chapter)
|
|
chapter_num += 1
|
|
|
|
# Group day entries by month
|
|
months_data = [] # List of { month, title, subChapters: [...] }
|
|
current_month_group = None
|
|
|
|
for entry in day_entries:
|
|
month = entry["month"]
|
|
month_full = entry["month_full"]
|
|
|
|
if current_month_group is None or current_month_group["month"] != month:
|
|
current_month_group = {
|
|
"month": month,
|
|
"title": month_full,
|
|
"subChapters": [],
|
|
}
|
|
months_data.append(current_month_group)
|
|
|
|
entry["number"] = chapter_num
|
|
current_month_group["subChapters"].append(
|
|
{
|
|
"slug": entry["slug"],
|
|
"title": entry["title"],
|
|
}
|
|
)
|
|
chapter_num += 1
|
|
|
|
# Build the intro.json chapters array
|
|
# Front matter chapters (preface, introduction) are top-level
|
|
# Month groups use the hierarchical sub-chapter pattern
|
|
intro_chapters = []
|
|
|
|
# Add preface and introduction as simple chapters
|
|
intro_chapters.append({"slug": "preface", "title": "Preface"})
|
|
intro_chapters.append({"slug": "introduction", "title": "Introduction"})
|
|
|
|
# Add month groups
|
|
for mg in months_data:
|
|
intro_chapters.append(
|
|
{
|
|
"title": mg["title"],
|
|
"subChapters": mg["subChapters"],
|
|
}
|
|
)
|
|
|
|
intro_json = {
|
|
"book": "jaladuta-diary",
|
|
"title": "The Jaladuta Diary, 1965 — Journey to the U.S.A.",
|
|
"author": "His Divine Grace A.C. Bhaktivedanta Swami Prabhupāda",
|
|
"year": 1965,
|
|
"description": "Śrīla Prabhupāda's personal diary kept during his historic voyage from Calcutta to New York aboard the cargo ship Jaladuta in 1965.",
|
|
"totalChapters": chapter_num - 1,
|
|
"chapters": intro_chapters,
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Phase 5: Write JSON files
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Clean output directory
|
|
if os.path.exists(chapters_dir):
|
|
for f in os.listdir(chapters_dir):
|
|
os.remove(os.path.join(chapters_dir, f))
|
|
|
|
# Write intro.json
|
|
write_json(intro_json, os.path.join(output_dir, "intro.json"))
|
|
print(f"\n Written: intro.json ({len(intro_chapters)} top-level entries)")
|
|
|
|
# Write preface
|
|
write_json(
|
|
{
|
|
"book": "jaladuta-diary",
|
|
"chapter": 1,
|
|
"title": "Preface",
|
|
"type": "preface",
|
|
"slug": "preface",
|
|
"paragraphs": preface_paragraphs,
|
|
},
|
|
os.path.join(chapters_dir, "preface.json"),
|
|
)
|
|
print(f" Written: preface.json ({len(preface_paragraphs)} paragraphs)")
|
|
|
|
# Write introduction
|
|
write_json(
|
|
{
|
|
"book": "jaladuta-diary",
|
|
"chapter": 2,
|
|
"title": "Introduction",
|
|
"type": "introduction",
|
|
"slug": "introduction",
|
|
"paragraphs": intro_paragraphs,
|
|
},
|
|
os.path.join(chapters_dir, "introduction.json"),
|
|
)
|
|
print(f" Written: introduction.json ({len(intro_paragraphs)} paragraphs)")
|
|
|
|
# Write day entries
|
|
ch_num = 3
|
|
for entry in day_entries:
|
|
slug = entry["slug"]
|
|
if not slug:
|
|
print(f" ⚠ Skipping entry with no slug: {entry.get('title', '?')}")
|
|
continue
|
|
|
|
chapter_data = {
|
|
"book": "jaladuta-diary",
|
|
"chapter": ch_num,
|
|
"title": entry["title"],
|
|
"type": "chapter",
|
|
"slug": slug,
|
|
"paragraphs": entry["paragraphs"],
|
|
}
|
|
write_json(chapter_data, os.path.join(chapters_dir, f"{slug}.json"))
|
|
ch_num += 1
|
|
|
|
total_files = 2 + len([e for e in day_entries if e.get("slug")])
|
|
print(f"\n Total chapter files written: {total_files}")
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Summary
|
|
# ---------------------------------------------------------------------------
|
|
print(f"\n{'=' * 60}")
|
|
print(f" EXTRACTION SUMMARY")
|
|
print(f"{'=' * 60}")
|
|
print(f" Preface: {len(preface_paragraphs)} paragraphs")
|
|
print(f" Introduction: {len(intro_paragraphs)} paragraphs")
|
|
print(f" Day entries: {len(day_entries)}")
|
|
for mg in months_data:
|
|
print(f" {mg['title']}: {len(mg['subChapters'])} entries")
|
|
for sc in mg["subChapters"]:
|
|
print(f" - {sc['slug']}: {sc['title']}")
|
|
print(f" Total chapters: {ch_num - 1}")
|
|
print(f"{'=' * 60}")
|
|
print(f"\nDone! ✨")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|