mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-02-04 10:54:44 -05:00
switched to NKJV, improved grading, improved styling
This commit is contained in:
302
plans/local-bible-xml-implementation.md
Normal file
302
plans/local-bible-xml-implementation.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# Local Bible XML Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Replace the external Bible API ([`fetchRandomVerse()`](../src/lib/server/bible-api.ts:6)) with a local XML-based solution using the downloaded NKJV Bible XML file.
|
||||
|
||||
## Current Implementation Analysis
|
||||
|
||||
### Current Flow
|
||||
|
||||
The system currently:
|
||||
|
||||
1. Calls [`fetchRandomVerse()`](../src/lib/server/bible-api.ts:6) which hits `https://bible-api.com`
|
||||
2. Gets a random verse position (book, chapter, verse)
|
||||
3. Fetches 3 consecutive verses starting from that position
|
||||
4. Returns `{ bookId, reference, verseText }` as [`ApiVerse`](../src/lib/server/bible-api.ts:4)
|
||||
5. Stores this in the database via [`getTodayVerse()`](../src/routes/+page.server.ts:11)
|
||||
|
||||
### Key Data Structures
|
||||
|
||||
- **Book IDs**: 3-letter codes (e.g., 'GEN', 'MAT', '1CO') defined in [`bibleBooks`](../src/lib/types/bible.ts:24)
|
||||
- **Book Order**: Sequential 1-66 via the `order` property
|
||||
- **Return Format**: `{ bookId: string, reference: string, verseText: string }`
|
||||
|
||||
### XML Structure
|
||||
|
||||
```xml
|
||||
<bible translation="English NKJ 1982">
|
||||
<testament name="Old">
|
||||
<book number="1">
|
||||
<chapter number="1">
|
||||
<verse number="1">Text here</verse>
|
||||
```
|
||||
|
||||
Books are numbered 1-66, matching the `order` property in [`bibleBooks`](../src/lib/types/bible.ts:24).
|
||||
|
||||
## Solution Architecture
|
||||
|
||||
### Book Number Mapping Strategy
|
||||
|
||||
Since the XML uses numbers (1-66) and the system uses book IDs ('GEN', 'MAT', etc.), we'll create a mapping using the existing [`bibleBooks`](../src/lib/types/bible.ts:24) array:
|
||||
|
||||
```typescript
|
||||
// book number -> book ID
|
||||
const bookNumberToId = {
|
||||
1: "GEN", // Genesis
|
||||
2: "EXO", // Exodus
|
||||
// ... through ...
|
||||
40: "MAT", // Matthew (first NT book)
|
||||
// ... to ...
|
||||
66: "REV", // Revelation
|
||||
};
|
||||
```
|
||||
|
||||
This can be generated programmatically from the existing [`bibleBooks`](../src/lib/types/bible.ts:24) array using the `order` property.
|
||||
|
||||
### XML Parsing Approach
|
||||
|
||||
We'll use a streaming/lazy approach to avoid loading the entire XML into memory:
|
||||
|
||||
1. **Random Selection**: Pick random book number (1-66), chapter, and verse
|
||||
2. **Targeted Parsing**: Parse only the needed section of the XML
|
||||
3. **Verse Extraction**: Extract 3 consecutive verses from that position
|
||||
|
||||
### Implementation Flow
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[getTodayVerse called] --> B[fetchRandomVerse]
|
||||
B --> C[Generate random position]
|
||||
C --> D[Load XML file]
|
||||
D --> E[Parse specific book/chapter]
|
||||
E --> F[Extract 3 consecutive verses]
|
||||
F --> G[Map book number to ID]
|
||||
G --> H[Format reference string]
|
||||
H --> I[Return ApiVerse object]
|
||||
I --> J[Store in database]
|
||||
```
|
||||
|
||||
## Technical Implementation Plan
|
||||
|
||||
### Step 1: Create Book Mapping Utility
|
||||
|
||||
**File**: [`src/lib/server/bible.ts`](../src/lib/server/bible.ts)
|
||||
|
||||
Add a new mapping object and helper function:
|
||||
|
||||
- Create `bookNumberToId` map derived from [`bibleBooks`](../src/lib/types/bible.ts:24)
|
||||
- Create `getBookByNumber(number: number): BibleBook | undefined`
|
||||
- Create reverse map `bookIdToNumber` for potential future use
|
||||
|
||||
### Step 2: Install XML Parser
|
||||
|
||||
**Command**: Install a lightweight XML parser
|
||||
|
||||
Options:
|
||||
|
||||
- `fast-xml-parser` - Fast, lightweight, good for selective parsing
|
||||
- `xml2js` - Popular, stable
|
||||
- Node's built-in stream parser for maximum efficiency
|
||||
|
||||
Recommendation: `fast-xml-parser` for balance of speed and ease of use.
|
||||
|
||||
### Step 3: Create XML Utility Module
|
||||
|
||||
**File**: `src/lib/server/xml-bible.ts` (new file)
|
||||
|
||||
Functions needed:
|
||||
|
||||
- `loadBibleXml()`: Read the XML file from disk
|
||||
- `parseBook(xml: string, bookNumber: number)`: Extract specific book data
|
||||
- `getChapterVerseCount(bookNumber: number, chapterNumber: number)`: Get verse count for validation
|
||||
- `extractVerses(bookNumber: number, chapter: number, startVerse: number, count: number)`: Get consecutive verses
|
||||
|
||||
### Step 4: Implement Random Verse Selection Logic
|
||||
|
||||
**File**: `src/lib/server/xml-bible.ts`
|
||||
|
||||
Algorithm:
|
||||
|
||||
1. Pick random book number (1-66)
|
||||
2. Parse that book to get chapter count
|
||||
3. Pick random chapter
|
||||
4. Parse that chapter to get verse count
|
||||
5. Pick random starting verse (ensuring room for 3 verses)
|
||||
6. Extract verses and verse count
|
||||
|
||||
**Optimization**: Consider pre-computing chapter/verse counts to avoid parsing overhead.
|
||||
|
||||
### Step 5: Create New fetchRandomVerse Implementation
|
||||
|
||||
**File**: [`src/lib/server/bible-api.ts`](../src/lib/server/bible-api.ts)
|
||||
|
||||
Replace the current implementation:
|
||||
|
||||
- Remove external API calls
|
||||
- Use new XML parsing functions
|
||||
- Maintain the same return type [`ApiVerse`](../src/lib/server/bible-api.ts:4)
|
||||
- Format reference string (e.g., "Matthew 1:1-3")
|
||||
|
||||
### Step 6: Handle Edge Cases
|
||||
|
||||
Important considerations:
|
||||
|
||||
- **End-of-chapter**: If starting verse is near end, may get fewer than 3 verses
|
||||
- **End-of-book**: Don't cross chapter boundaries
|
||||
- **Short chapters**: Some chapters have only 1-2 verses
|
||||
- **Book names**: Generate proper reference strings (e.g., "1 Samuel" not "1SA")
|
||||
|
||||
### Step 7: Testing Strategy
|
||||
|
||||
1. **Manual testing**: Run the app and verify verses load correctly
|
||||
2. **Verify book mapping**: Ensure all 66 books map correctly
|
||||
3. **Check reference format**: Ensure references match expected format
|
||||
4. **Edge case testing**: Test with short chapters/books
|
||||
5. **Performance**: Ensure parsing is fast enough for production
|
||||
|
||||
## Data Structure Details
|
||||
|
||||
### Book Number to ID Mapping
|
||||
|
||||
```typescript
|
||||
// Complete mapping based on existing bibleBooks array
|
||||
const BOOK_MAPPING = {
|
||||
// Old Testament (1-39)
|
||||
1: "GEN",
|
||||
2: "EXO",
|
||||
3: "LEV",
|
||||
4: "NUM",
|
||||
5: "DEU",
|
||||
6: "JOS",
|
||||
7: "JDG",
|
||||
8: "RUT",
|
||||
9: "1SA",
|
||||
10: "2SA",
|
||||
11: "1KI",
|
||||
12: "2KI",
|
||||
13: "1CH",
|
||||
14: "2CH",
|
||||
15: "EZR",
|
||||
16: "NEH",
|
||||
17: "EST",
|
||||
18: "JOB",
|
||||
19: "PSA",
|
||||
20: "PRO",
|
||||
21: "ECC",
|
||||
22: "SNG",
|
||||
23: "ISA",
|
||||
24: "JER",
|
||||
25: "LAM",
|
||||
26: "EZK",
|
||||
27: "DAN",
|
||||
28: "HOS",
|
||||
29: "JOL",
|
||||
30: "AMO",
|
||||
31: "OBA",
|
||||
32: "JON",
|
||||
33: "MIC",
|
||||
34: "NAM",
|
||||
35: "HAB",
|
||||
36: "ZEP",
|
||||
37: "HAG",
|
||||
38: "ZEC",
|
||||
39: "MAL",
|
||||
// New Testament (40-66)
|
||||
40: "MAT",
|
||||
41: "MRK",
|
||||
42: "LUK",
|
||||
43: "JHN",
|
||||
44: "ACT",
|
||||
45: "ROM",
|
||||
46: "1CO",
|
||||
47: "2CO",
|
||||
48: "GAL",
|
||||
49: "EPH",
|
||||
50: "PHP",
|
||||
51: "COL",
|
||||
52: "1TH",
|
||||
53: "2TH",
|
||||
54: "1TI",
|
||||
55: "2TI",
|
||||
56: "TIT",
|
||||
57: "PHM",
|
||||
58: "HEB",
|
||||
59: "JAS",
|
||||
60: "1PE",
|
||||
61: "2PE",
|
||||
62: "1JN",
|
||||
63: "2JN",
|
||||
64: "3JN",
|
||||
65: "JUD",
|
||||
66: "REV",
|
||||
};
|
||||
```
|
||||
|
||||
### Reference String Format
|
||||
|
||||
The reference should match the current format from the API:
|
||||
|
||||
- Format: `"{Book Name} {Chapter}:{StartVerse}-{EndVerse}"`
|
||||
- Example: `"Matthew 1:1-3"` or `"1 Corinthians 13:4-6"`
|
||||
|
||||
Use the `name` property from the [`BibleBook`](../src/lib/types/bible.ts:14) interface.
|
||||
|
||||
## File Changes Summary
|
||||
|
||||
### New Files
|
||||
|
||||
- `src/lib/server/xml-bible.ts` - XML parsing and verse extraction logic
|
||||
|
||||
### Modified Files
|
||||
|
||||
- [`src/lib/server/bible.ts`](../src/lib/server/bible.ts) - Add book number mapping utilities
|
||||
- [`src/lib/server/bible-api.ts`](../src/lib/server/bible-api.ts) - Replace API calls with local XML parsing
|
||||
- `package.json` - Add XML parser dependency
|
||||
|
||||
### No Changes Required
|
||||
|
||||
- [`src/routes/+page.server.ts`](../src/routes/+page.server.ts) - Uses [`fetchRandomVerse()`](../src/lib/server/bible-api.ts:6), internal implementation change is transparent
|
||||
- [`src/lib/types/bible.ts`](../src/lib/types/bible.ts) - Existing types remain the same
|
||||
- Database schema - No changes needed
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Memory Usage
|
||||
|
||||
- Avoid loading entire XML file into memory
|
||||
- Parse only the needed book/chapter sections
|
||||
- Use streaming or selective parsing
|
||||
|
||||
### Speed Optimization Options
|
||||
|
||||
1. **Lazy parsing**: Only parse when needed (slower, low memory)
|
||||
2. **Pre-parsed index**: Create JSON index of book/chapter/verse counts (faster, more memory)
|
||||
3. **Caching**: Cache parsed books in memory during runtime (fastest, higher memory)
|
||||
|
||||
Recommendation: Start with lazy parsing, optimize if needed.
|
||||
|
||||
### File Size
|
||||
|
||||
The XML file is large but will be read from disk once per verse generation. Since verses are cached per day in the database, this happens once daily.
|
||||
|
||||
## Rollback Strategy
|
||||
|
||||
If issues arise:
|
||||
|
||||
1. Keep the old [`fetchRandomVerse()`](../src/lib/server/bible-api.ts:6) implementation as `fetchRandomVerseAPI()`
|
||||
2. Add environment variable to toggle between implementations
|
||||
3. Can quickly revert by changing which function is exported
|
||||
|
||||
## Next Steps After Implementation
|
||||
|
||||
1. Monitor daily verse generation for errors
|
||||
2. Verify reference strings are formatted correctly
|
||||
3. Consider adding verse length validation (avoid very short/long passages)
|
||||
4. Potentially add weighted random selection to favor popular books
|
||||
|
||||
## Questions to Resolve
|
||||
|
||||
1. Should we validate that selected verses have minimum text length?
|
||||
2. Should we add any filtering to avoid certain books or chapters?
|
||||
3. Do we want to pre-compute chapter/verse counts for faster selection?
|
||||
Reference in New Issue
Block a user