Rebuild Scripture Index as a true cross-content reference index
Publish Container / docker (push) Successful in 15m2s

Previously it just grouped study lessons under each study (essentially
another list of lessons) and ignored podcast episodes entirely. Now it
parses every reference from studies and episode show notes, merges
entries that point at the same verse(s) into one row with links to all
sources, and groups rows by book in canonical Bible order. References
that don't parse (e.g. whole-chapter refs) fall into an "Other
References" section instead of being dropped.

Also fixes the reference passed to the index for studies without a
bibleBook set — it was falling back to the study's marketing title
instead of its slug, producing unparseable references.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Yvx4rPVy2HWe7ubuk3X3J
This commit is contained in:
nmemmertandClaude Sonnet 5 committed 2026-09-07 09:20:12 -04:00
1 parent 274adcc093
commit 6ed29ea527
3 files changed
+254 -85

No files matched your search

+34 -13
View File
@@ -159,23 +159,44 @@ export function register(app) {
</html>`)
})
// Scripture index — all released study lessons with their passage references
// Scripture index — every passage covered across released study lessons and podcast episodes
app.get('/api/public/scripture-index', (_req, res) => {
const content = state.cachedSiteContent
const allStudies = Array.isArray(content?.studies) ? content.studies : []
const allEpisodes = Array.isArray(content?.podcastFeaturedLinks) ? content.podcastFeaturedLinks : []
const cutoff = new Date()
const studies = allStudies
.filter(s => s.slug && Array.isArray(s.sections))
.map(s => ({
slug: s.slug,
title: s.title || s.slug,
entries: s.sections
.filter(sec => sec.id && sec.reference && sec.releasedAt && new Date(sec.releasedAt) <= cutoff)
.map(sec => ({ sectionId: sec.id, title: sec.title || '', reference: sec.reference }))
.sort((a, b) => a.reference.localeCompare(b.reference, undefined, { numeric: true })),
}))
.filter(s => s.entries.length > 0)
res.json({ studies })
const entries = []
for (const s of allStudies) {
if (!s.slug || !Array.isArray(s.sections)) continue
const bookName = s.bibleBook || s.slug
for (const sec of s.sections) {
if (!sec.id || !sec.reference || !sec.releasedAt) continue
if (new Date(sec.releasedAt) > cutoff) continue
entries.push({
reference: `${bookName} ${sec.reference}`,
sourceType: 'study',
sourceTitle: s.title || s.slug,
sectionTitle: sec.title || '',
url: `/study/${s.slug}/${sec.id}`,
})
}
}
for (const ep of allEpisodes) {
if (!ep.id || !Array.isArray(ep.showNotesScripture)) continue
for (const ref of ep.showNotesScripture) {
if (!ref || !ref.trim()) continue
entries.push({
reference: ref.trim(),
sourceType: 'episode',
sourceTitle: ep.episodeNumber ? `Episode ${ep.episodeNumber}: ${ep.title}` : (ep.title || 'Episode'),
url: `/episodes/${ep.id}`,
})
}
}
res.json({ entries })
})
// SPA static files and fallback