Files
kjvstudy.org/kjvstudy_org/stories.py
T
kennethreitz 7522b27e7c Implement Phase 2 performance optimizations
1. Replace regex markdown with mistune library
   - Add mistune>=3.0.2 dependency
   - Replace custom regex patterns with proper markdown parser
   - Better performance and more robust parsing
   - Supports full markdown syntax (bold, italic, strikethrough, etc.)

2. Cache story counts
   - Cache get_story_count() and get_category_count()
   - Expected: 10-20x faster story index page loads
   - Added cache invalidation to refresh_stories()

3. Fix O(n) pattern in helpers.py
   - Replace manual chapter filtering with bible.get_chapters_for_book()
   - Uses existing @lru_cache for instant lookups

Combined expected improvement: 10-20% on story pages, faster markdown

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 12:06:13 -05:00

128 lines
3.7 KiB
Python

"""Bible Stories data loader.
Loads all story JSON files and provides access to stories by category and slug.
"""
import json
from pathlib import Path
from typing import Optional
# Path to stories directory
STORIES_DIR = Path(__file__).parent / "data" / "stories"
def load_all_stories() -> list[dict]:
"""Load all story categories from JSON files."""
categories = []
if not STORIES_DIR.exists():
return categories
# Load JSON files in order (they're numbered)
json_files = sorted(STORIES_DIR.glob("*.json"))
for json_file in json_files:
try:
with open(json_file, "r", encoding="utf-8") as f:
category_data = json.load(f)
categories.append(category_data)
except (json.JSONDecodeError, IOError) as e:
print(f"Error loading {json_file}: {e}")
continue
return categories
def get_all_stories_flat() -> list[dict]:
"""Get all stories as a flat list with category info attached."""
categories = load_all_stories()
all_stories = []
for category in categories:
category_name = category.get("category", "Unknown")
category_slug = category.get("slug", "unknown")
for story in category.get("stories", []):
story_with_category = story.copy()
story_with_category["category_name"] = category_name
story_with_category["category_slug"] = category_slug
all_stories.append(story_with_category)
return all_stories
def get_story_by_slug(slug: str) -> Optional[dict]:
"""Find a story by its slug."""
for story in get_all_stories_flat():
if story.get("slug") == slug:
return story
return None
def get_stories_by_category(category_slug: str) -> list[dict]:
"""Get all stories in a specific category."""
categories = load_all_stories()
for category in categories:
if category.get("slug") == category_slug:
stories = []
for story in category.get("stories", []):
story_with_category = story.copy()
story_with_category["category_name"] = category.get("category", "Unknown")
story_with_category["category_slug"] = category_slug
stories.append(story_with_category)
return stories
return []
def get_category_by_slug(category_slug: str) -> Optional[dict]:
"""Get a category by its slug."""
categories = load_all_stories()
for category in categories:
if category.get("slug") == category_slug:
return category
return None
# Cache story counts
_CACHED_STORY_COUNT = None
_CACHED_CATEGORY_COUNT = None
def get_story_count() -> int:
"""Get total number of stories (cached)."""
global _CACHED_STORY_COUNT
if _CACHED_STORY_COUNT is None:
_CACHED_STORY_COUNT = len(get_all_stories_flat())
return _CACHED_STORY_COUNT
def get_category_count() -> int:
"""Get total number of categories (cached)."""
global _CACHED_CATEGORY_COUNT
if _CACHED_CATEGORY_COUNT is None:
_CACHED_CATEGORY_COUNT = len(load_all_stories())
return _CACHED_CATEGORY_COUNT
# Pre-load categories on module import for faster access
STORY_CATEGORIES = None
def get_categories() -> list[dict]:
"""Get all categories (cached)."""
global STORY_CATEGORIES
if STORY_CATEGORIES is None:
STORY_CATEGORIES = load_all_stories()
return STORY_CATEGORIES
def refresh_stories():
"""Refresh the cached stories (useful after adding new files)."""
global STORY_CATEGORIES, _CACHED_STORY_COUNT, _CACHED_CATEGORY_COUNT
STORY_CATEGORIES = load_all_stories()
_CACHED_STORY_COUNT = None
_CACHED_CATEGORY_COUNT = None