mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 14:50:17 +00:00
121 lines
3.5 KiB
Python
121 lines
3.5 KiB
Python
"""
|
|
Topical index for finding Bible verses by theme.
|
|
Organized by major theological and practical topics.
|
|
"""
|
|
|
|
import json
|
|
from functools import lru_cache
|
|
from pathlib import Path
|
|
|
|
from typing import Dict, Any
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _load_topics():
|
|
"""Load topics from per-topic JSON files, fallback to legacy single file."""
|
|
base_dir = Path(__file__).parent / "data"
|
|
topics_dir = base_dir / "topics"
|
|
legacy_path = base_dir / "topics.json"
|
|
|
|
aggregated = {}
|
|
if topics_dir.exists():
|
|
for path in sorted(topics_dir.glob("*.json")):
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
content = json.load(f)
|
|
if isinstance(content, dict):
|
|
aggregated.update(content)
|
|
elif legacy_path.exists():
|
|
with open(legacy_path, "r", encoding="utf-8") as f:
|
|
aggregated = json.load(f)
|
|
|
|
return aggregated
|
|
|
|
|
|
def _get_verse_text_for_reference(reference: str) -> str:
|
|
"""Look up a single verse text from a reference like 'John 3:16'."""
|
|
if not reference or not isinstance(reference, str):
|
|
return ""
|
|
|
|
parts = reference.rsplit(" ", 1)
|
|
if len(parts) != 2 or ":" not in parts[1]:
|
|
return ""
|
|
|
|
book = parts[0]
|
|
chapter_part, verse_part = parts[1].split(":", 1)
|
|
# Use the first verse in a range (e.g., 3:16-17 -> 3:16)
|
|
verse_segment = verse_part.split("-")[0]
|
|
|
|
try:
|
|
from .kjv import bible
|
|
return bible.get_verse_text(book, int(chapter_part), int(verse_segment)) or ""
|
|
except Exception:
|
|
return ""
|
|
|
|
|
|
def _enrich_topic_with_text(topic: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Attach verse text (and normalized reference fields) to a topic's verses."""
|
|
subtopics = topic.get("subtopics", {})
|
|
enriched_subtopics = {}
|
|
|
|
for subtopic_name, subtopic_data in subtopics.items():
|
|
verses_with_text = []
|
|
for entry in subtopic_data.get("verses", []):
|
|
if isinstance(entry, dict):
|
|
reference = entry.get("reference") or entry.get("ref") or ""
|
|
note = entry.get("note", "")
|
|
else:
|
|
reference = str(entry)
|
|
note = ""
|
|
|
|
verse_text = _get_verse_text_for_reference(reference)
|
|
verses_with_text.append({
|
|
"reference": reference,
|
|
"ref": reference,
|
|
"text": verse_text,
|
|
"note": note
|
|
})
|
|
|
|
enriched_subtopics[subtopic_name] = {
|
|
**subtopic_data,
|
|
"verses": verses_with_text
|
|
}
|
|
|
|
return {
|
|
**topic,
|
|
"subtopics": enriched_subtopics
|
|
}
|
|
|
|
|
|
def get_all_topics():
|
|
"""Get all topics"""
|
|
return _load_topics()
|
|
|
|
|
|
def get_topic(topic_name: str):
|
|
"""Get a specific topic"""
|
|
return _load_topics().get(topic_name)
|
|
|
|
|
|
@lru_cache(maxsize=None)
|
|
def get_topic_with_text(topic_name: str):
|
|
"""Get a topic with verse text attached to each reference."""
|
|
topic = _load_topics().get(topic_name)
|
|
if not topic:
|
|
return None
|
|
return _enrich_topic_with_text(topic)
|
|
|
|
|
|
def search_topics(query: str):
|
|
"""Search for topics by name or description"""
|
|
query_lower = query.lower()
|
|
results = []
|
|
|
|
for topic_name, topic_data in _load_topics().items():
|
|
if query_lower in topic_name.lower() or query_lower in topic_data.get("description", "").lower():
|
|
results.append({
|
|
"name": topic_name,
|
|
"description": topic_data["description"],
|
|
"subtopic_count": len(topic_data.get("subtopics", {}))
|
|
})
|
|
|
|
return results
|