mirror of
https://github.com/kennethreitz/kjvstudy.org.git
synced 2026-06-05 23:00:16 +00:00
91b2e2cab0
Previously, stories.py loaded all story JSON files on every request and timeline.py loaded biblical_timeline.json on every request. Now both use module-level caching for better performance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
141 lines
4.0 KiB
Python
141 lines
4.0 KiB
Python
"""Bible Stories data loader.
|
|
|
|
Loads all story JSON files and provides access to stories by category and slug.
|
|
"""
|
|
import json
|
|
from functools import lru_cache
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
# Path to stories directory
|
|
STORIES_DIR = Path(__file__).parent / "data" / "stories"
|
|
|
|
|
|
def _load_all_stories_uncached() -> list[dict]:
|
|
"""Load all story categories from JSON files (internal, uncached)."""
|
|
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
|
|
|
|
|
|
# Load stories once at module import time
|
|
_STORIES_CACHE: list[dict] | None = None
|
|
|
|
|
|
def load_all_stories() -> list[dict]:
|
|
"""Load all story categories from JSON files (cached)."""
|
|
global _STORIES_CACHE
|
|
if _STORIES_CACHE is None:
|
|
_STORIES_CACHE = _load_all_stories_uncached()
|
|
return _STORIES_CACHE
|
|
|
|
|
|
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
|