mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
1279fde038
URLs like /book/gen/chapter/1/verse/3 now properly redirect to /book/Genesis/chapter/1/verse/3 with a 301 status. The normalize_book_name function now does case-insensitive lookup for both abbreviations and canonical book names. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
"""Book name normalization and categorization utilities."""
|
|
import json
|
|
from pathlib import Path
|
|
from functools import lru_cache
|
|
from typing import Optional
|
|
|
|
# Path to bible metadata JSON file
|
|
_METADATA_PATH = Path(__file__).parent.parent / "data" / "bible_metadata.json"
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _load_bible_metadata() -> dict:
|
|
"""
|
|
Load bible metadata from JSON file.
|
|
Cached since this data never changes and is accessed frequently.
|
|
"""
|
|
with open(_METADATA_PATH, "r", encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
# Load data from JSON
|
|
_metadata = _load_bible_metadata()
|
|
OT_BOOKS = _metadata["old_testament_books"]
|
|
NT_BOOKS = _metadata["new_testament_books"]
|
|
BOOK_ABBREVIATIONS = _metadata["book_abbreviations"]
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _get_lowercase_abbreviations() -> dict:
|
|
"""Create a lowercase mapping of abbreviations for case-insensitive lookup."""
|
|
return {k.lower(): v for k, v in BOOK_ABBREVIATIONS.items()}
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _get_lowercase_canonical_names() -> dict:
|
|
"""Create a lowercase mapping of canonical book names."""
|
|
all_books = OT_BOOKS + NT_BOOKS
|
|
return {b.lower(): b for b in all_books}
|
|
|
|
|
|
def normalize_book_name(book: str) -> Optional[str]:
|
|
"""
|
|
Normalize book name variations to canonical form.
|
|
Returns the canonical book name if a variation is detected, None otherwise.
|
|
Case-insensitive lookup.
|
|
"""
|
|
# First try exact match in abbreviations
|
|
if book in BOOK_ABBREVIATIONS:
|
|
return BOOK_ABBREVIATIONS[book]
|
|
# Then try case-insensitive match in abbreviations
|
|
lowercase_abbrevs = _get_lowercase_abbreviations()
|
|
result = lowercase_abbrevs.get(book.lower())
|
|
if result:
|
|
return result
|
|
# Finally, check if it's a case variation of a canonical name
|
|
lowercase_canonical = _get_lowercase_canonical_names()
|
|
canonical = lowercase_canonical.get(book.lower())
|
|
if canonical and canonical != book:
|
|
return canonical
|
|
return None
|
|
|
|
|
|
def is_old_testament(book: str) -> bool:
|
|
"""Check if a book is in the Old Testament."""
|
|
return book in OT_BOOKS
|
|
|
|
|
|
def is_new_testament(book: str) -> bool:
|
|
"""Check if a book is in the New Testament."""
|
|
return book in NT_BOOKS
|
|
|
|
|
|
def get_testament(book: str) -> str:
|
|
"""Return the testament name for a book."""
|
|
if is_old_testament(book):
|
|
return "Old Testament"
|
|
elif is_new_testament(book):
|
|
return "New Testament"
|
|
return "Unknown"
|