// The Bibles the Reader can show, and one way to fetch a chapter of any of them. Used by the // main reading text, the side-by-side view, and the verse "Compare" tab. import { CHAPTER_COUNTS, parseBibleChapter } from './bibleUtils.jsx'; export const READER_TRANSLATIONS = [ { id: 'BSB', name: 'Berean Standard Bible' }, { id: 'ESV', name: 'English Standard Version', licensed: true, notice: 'Scripture quotations are from the ESV® Bible (The Holy Bible, English Standard Version®), © 2001 by Crossway, a publishing ministry of Good News Publishers. Used by permission. All rights reserved.' }, { id: 'NET', name: 'NET Bible', helloao: 'eng_net', notice: 'Scripture quoted by permission. Quotations designated (NET) are from the NET Bible® copyright ©1996-2017 by Biblical Studies Press, L.L.C. http://netbible.com All rights reserved.' }, { id: 'KJV', name: 'King James Version', helloao: 'eng_kjv', notice: 'The King James Version is in the public domain.' }, { id: 'ASV', name: 'American Standard Version (1901)', helloao: 'eng_asv', notice: 'The American Standard Version (1901) is in the public domain.' }, { id: 'LSV', name: 'Literal Standard Version', helloao: 'eng_lsv', notice: 'Literal Standard Version © 2020 Covenant Press and the Covenant Christian Coalition. Free to read and share. lsvbible.com' }, { id: 'NLT', name: 'New Living Translation', licensed: true, notice: 'Holy Bible, New Living Translation, Copyright © 2014, Tyndale House Publishers. All rights reserved. tyndale.com' }, { id: 'CSB', name: 'Christian Standard Bible', licensed: true, notice: 'Christian Standard Bible® and CSB® are federally registered trademarks of Holman Bible Publishers. All rights reserved. bhpublishinggroup.com' }, { id: 'NASB', name: 'New American Standard Bible', licensed: true, notice: 'New American Standard Bible®, Copyright © 1995, The Lockman Foundation. All rights reserved. lockman.org' }, ]; // The address code helloao uses for a translation (NET is 'eng_net', the KJV 'eng_kjv'; BSB is its own) export const helloaoCode = (id) => READER_TRANSLATIONS.find((t) => t.id === id)?.helloao ?? id ?? 'BSB'; export const translationName = (id) => READER_TRANSLATIONS.find((t) => t.id === id)?.name ?? id; export const isLicensed = (id) => READER_TRANSLATIONS.find((t) => t.id === id)?.licensed === true; // Free translations are kept for the visit so flipping between chapters, the side-by-side // view and Compare don't re-download. Licensed text is never kept here (their terms limit // storage); the server holds it briefly. const freeChapters = new Map(); // "BSB/JHN/3" -> { verses, totalChapters } export const clearChapterCache = () => freeChapters.clear(); // -> { verses: [{ number, text }], copyright, totalChapters }. Throws Error(message) on failure. // Pass `signal` to cancel a request that is no longer wanted. export async function fetchChapter(translation, bookAbbrev, chapter, { signal } = {}) { const source = READER_TRANSLATIONS.find((t) => t.id === translation) ?? READER_TRANSLATIONS[0]; let totalChapters = CHAPTER_COUNTS[bookAbbrev] ?? chapter; if (!source.licensed) { const key = `${source.id}/${bookAbbrev}/${chapter}`; const hit = freeChapters.get(key); if (hit) return { verses: hit.verses, copyright: '', totalChapters: hit.totalChapters }; const res = await fetch(`https://bible.helloao.org/api/${source.helloao ?? source.id}/${bookAbbrev}/${chapter}.json`, { signal }); if (!res.ok) throw new Error('Unable to load chapter.'); const data = await res.json(); const verses = parseBibleChapter(data); if (!Array.isArray(verses) || verses.length === 0) throw new Error('Invalid Bible data returned.'); totalChapters = data.book?.numberOfChapters ?? totalChapters; freeChapters.set(key, { verses, totalChapters }); return { verses, copyright: '', totalChapters }; } const res = await fetch(`/api/bible/${source.id}/${bookAbbrev}/${chapter}`, { credentials: 'include', signal }); const data = await res.json().catch(() => ({})); if (!res.ok) throw new Error(data.error || `Unable to load ${source.id}.`); if (!Array.isArray(data.verses) || data.verses.length === 0) throw new Error('Invalid Bible data returned.'); return { verses: data.verses, copyright: data.copyright ?? '', totalChapters }; }