waha-shared 1.0.308 → 1.0.309
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/areas/areas.json +50 -48
- package/dist/data/areas/areas.schema.json +2 -2
- package/dist/data/areas/areas.zod.d.ts +1 -1
- package/dist/data/areas/areas.zod.js +1 -1
- package/dist/data/areas/index.d.ts +1 -1
- package/dist/data/bibleAudios/bibleAudios.json +581 -314
- package/dist/data/bibleAudios/bibleAudios.schema.json +17 -8
- package/dist/data/bibleAudios/bibleAudios.zod.d.ts +43 -2
- package/dist/data/bibleAudios/bibleAudios.zod.js +16 -7
- package/dist/data/bibleAudios/index.d.ts +2 -1
- package/dist/data/bibleBooks/bibleBooks.json +792 -790
- package/dist/data/bibleStatuses/bibleStatuses.json +8023 -8801
- package/dist/data/bibleStatuses/bibleStatuses.schema.json +6 -0
- package/dist/data/bibleStatuses/bibleStatuses.zod.d.ts +1 -0
- package/dist/data/bibleStatuses/bibleStatuses.zod.js +4 -0
- package/dist/data/bibleStatuses/index.d.ts +1 -0
- package/dist/data/bibleTexts/bibleTexts.json +274 -187
- package/dist/data/bibleTexts/bibleTexts.schema.json +7 -0
- package/dist/data/bibleTexts/bibleTexts.zod.d.ts +28 -0
- package/dist/data/bibleTexts/bibleTexts.zod.js +10 -3
- package/dist/data/bibleTexts/index.d.ts +2 -0
- package/dist/data/clones/clones.json +2 -0
- package/dist/data/countries/countries.json +480 -480
- package/dist/data/countriesAndLanguages/countriesAndLanguages.json +6812 -6810
- package/dist/data/crowdinLanguages/crowdinLanguages.json +1440 -1438
- package/dist/data/crowdinLanguages/crowdinLanguages.schema.json +3 -3
- package/dist/data/crowdinLanguages/crowdinLanguages.zod.d.ts +2 -2
- package/dist/data/crowdinLanguages/crowdinLanguages.zod.js +2 -2
- package/dist/data/crowdinLanguages/index.d.ts +2 -2
- package/dist/data/curriculumFoundations/curriculumFoundations.json +86 -69
- package/dist/data/curriculumOnboarding/curriculumOnboarding.json +34 -0
- package/dist/data/curriculumOnboarding/curriculumOnboarding.schema.json +38 -0
- package/dist/data/curriculumOnboarding/curriculumOnboarding.zod.d.ts +11 -0
- package/dist/data/curriculumOnboarding/curriculumOnboarding.zod.js +18 -0
- package/dist/data/curriculumOnboarding/index.d.ts +9 -0
- package/dist/data/curriculumOnboarding/index.js +7 -0
- package/dist/data/curriculumQuestions/curriculumQuestions.json +194 -192
- package/dist/data/curriculumTopics/curriculumTopics.json +51 -8
- package/dist/data/dblAudioLicenses/dblAudioLicenses.json +450 -421
- package/dist/data/dblTextLicenses/dblTextLicenses.json +1251 -1161
- package/dist/data/firebase.d.ts +1 -0
- package/dist/data/firebase.js +4 -0
- package/dist/data/iosVoiceOverLanguages/iosVoiceOverLanguages.json +1 -1
- package/dist/data/iso6933LanguageCodes/iso6933LanguageCodes.json +1 -1
- package/dist/data/languages/index.d.ts +22 -10
- package/dist/data/languages/languages.json +3295 -2010
- package/dist/data/languages/languages.schema.json +102 -48
- package/dist/data/languages/languages.zod.d.ts +96 -30
- package/dist/data/languages/languages.zod.js +66 -37
- package/dist/data/lessonPauses/index.d.ts +0 -1
- package/dist/data/lessonPauses/lessonPauses.json +2 -3
- package/dist/data/lessonPauses/lessonPauses.schema.json +1 -11
- package/dist/data/lessonPauses/lessonPauses.zod.d.ts +0 -1
- package/dist/data/lessonPauses/lessonPauses.zod.js +0 -3
- package/dist/data/mediaDurations/mediaDurations.json +35288 -6076
- package/dist/data/mediaDurations/mediaDurations.schema.json +1 -1
- package/dist/data/mediaDurations/mediaDurations.zod.js +1 -1
- package/dist/data/notification/index.d.ts +1 -1
- package/dist/data/notification/notification.json +93 -169
- package/dist/data/phoneLanguages/phoneLanguages.json +637 -635
- package/dist/data/questions/questions.json +149 -147
- package/dist/data/releaseNotes/releaseNotes.json +169 -123
- package/dist/data/screenshots/screenshots.json +1 -1
- package/dist/data/scripts/scripts.json +6 -1
- package/dist/data/sets/index.d.ts +3 -3
- package/dist/data/sets/sets.json +1770 -480
- package/dist/data/sets/sets.schema.json +1 -1
- package/dist/data/sets/sets.zod.d.ts +3 -3
- package/dist/data/sets/sets.zod.js +3 -6
- package/dist/data/translationsApp/index.d.ts +1 -0
- package/dist/data/translationsApp/translationsApp.json +1610 -1569
- package/dist/data/translationsApp/translationsApp.schema.json +3 -1
- package/dist/data/translationsApp/translationsApp.zod.d.ts +2 -0
- package/dist/data/translationsApp/translationsApp.zod.js +1 -0
- package/dist/data/translationsFtb/translationsFtb.json +120 -664
- package/dist/data/translationsIntroduction/translationsIntroduction.json +1 -1
- package/dist/data/translationsQuestion/translationsQuestion.json +65 -33
- package/dist/data/translationsSet/translationsSet.json +30181 -19444
- package/dist/data/translationsSet/translationsSet.schema.json +3 -4
- package/dist/data/translationsSet/translationsSet.zod.js +4 -4
- package/dist/data/translationsSolarSpeaker/translationsSolarSpeaker.json +1 -1
- package/dist/data/translationsSpokenQuestion/translationsSpokenQuestion.json +65 -33
- package/dist/data/youtubePlaylists/youtubePlaylists.json +10 -10
- package/dist/data/youtubeVideos/youtubeVideos.json +82 -82
- package/dist/functions/bibleBooks.d.ts +16 -0
- package/dist/functions/bibleBooks.js +101 -0
- package/dist/functions/bibles.d.ts +47 -0
- package/dist/functions/bibles.js +314 -0
- package/dist/functions/languages.d.ts +6 -7
- package/dist/functions/languages.js +58 -53
- package/dist/functions/scripturePassages.d.ts +53 -47
- package/dist/functions/scripturePassages.js +217 -303
- package/dist/functions/sets.d.ts +13 -52
- package/dist/functions/sets.js +195 -205
- package/dist/functions/utils.d.ts +2 -0
- package/dist/functions/utils.js +8 -0
- package/dist/types/bibleChapters.d.ts +2 -2
- package/dist/types/bibleChapters.js +1 -1
- package/dist/types/languages.d.ts +48 -9
- package/dist/types/languages.js +2 -0
- package/dist/types/scripturePassages.d.ts +0 -1
- package/dist/types/scripturePassages.js +0 -1
- package/dist/types/sets.d.ts +28 -11
- package/package.json +1 -1
- package/dist/data/languageAssets/index.d.ts +0 -1
- package/dist/data/languageAssets/index.js +0 -7
- package/dist/data/languageAssets/languageAssets.json +0 -45406
- package/dist/data/languageAssets/languageAssets.schema.json +0 -19
- package/dist/data/languageAssets/languageAssets.zod.d.ts +0 -3
- package/dist/data/languageAssets/languageAssets.zod.js +0 -7
|
@@ -1,61 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseVerseRange =
|
|
3
|
+
exports.parseVerseRange = void 0;
|
|
4
4
|
exports.getChapterUrl = getChapterUrl;
|
|
5
5
|
exports.getPassagesString = getPassagesString;
|
|
6
|
+
exports.withChapterPlaceholders = withChapterPlaceholders;
|
|
6
7
|
exports.getScripturePassage = getScripturePassage;
|
|
7
8
|
exports.getLessonScripture = getLessonScripture;
|
|
8
|
-
exports.parseBibleSnapshot = parseBibleSnapshot;
|
|
9
9
|
exports.verseToSuperscript = verseToSuperscript;
|
|
10
|
-
exports.
|
|
10
|
+
exports.getFtbDuration = getFtbDuration;
|
|
11
|
+
exports.enrichSections = enrichSections;
|
|
11
12
|
exports.normalizeVerseTimings = normalizeVerseTimings;
|
|
12
13
|
const bibleStatuses_1 = require("../data/bibleStatuses");
|
|
13
|
-
const
|
|
14
|
+
const firebase_1 = require("../data/firebase");
|
|
14
15
|
const mediaDurations_1 = require("../data/mediaDurations");
|
|
15
|
-
const specialIds_1 = require("../data/specialIds");
|
|
16
16
|
const languages_1 = require("../functions/languages");
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
function parseVerseRange(passageId) {
|
|
24
|
-
// Handle single verse: "GEN.1.1" -> "GEN.1.1-GEN.1.1"
|
|
25
|
-
const parts = passageId.includes('-')
|
|
26
|
-
? passageId.split('-')
|
|
27
|
-
: [passageId, passageId];
|
|
28
|
-
const startParts = parts[0].split('.');
|
|
29
|
-
const endParts = parts[1].split('.');
|
|
30
|
-
const startBook = startParts[0];
|
|
31
|
-
const startChapter = startParts[1];
|
|
32
|
-
const startVerse = startParts.length > 2 ? startParts[2] : '1';
|
|
33
|
-
const endBook = endParts[0];
|
|
34
|
-
const endChapter = endParts[1];
|
|
35
|
-
const endVerse = endParts.length > 2 ? endParts[2] : '1';
|
|
36
|
-
return {
|
|
37
|
-
startBook,
|
|
38
|
-
startChapter,
|
|
39
|
-
startVerse,
|
|
40
|
-
endBook,
|
|
41
|
-
endChapter,
|
|
42
|
-
endVerse,
|
|
43
|
-
startChapterId: `${startBook}.${startChapter}`,
|
|
44
|
-
endChapterId: `${endBook}.${endChapter}`,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
17
|
+
const sets_1 = require("../types/sets");
|
|
18
|
+
const bibleBooks_1 = require("./bibleBooks");
|
|
19
|
+
const bibles_1 = require("./bibles");
|
|
20
|
+
var bibleBooks_2 = require("./bibleBooks");
|
|
21
|
+
Object.defineProperty(exports, "parseVerseRange", { enumerable: true, get: function () { return bibleBooks_2.parseVerseRange; } });
|
|
47
22
|
function getChapterUrl(params) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
: parseVerseRange(params.passageId).startChapter;
|
|
54
|
-
return (sets_1.firebaseUrl +
|
|
23
|
+
const book = 'book' in params ? params.book : (0, bibleBooks_1.parseVerseRange)(params.passageId).book;
|
|
24
|
+
const chapter = 'chapter' in params
|
|
25
|
+
? params.chapter
|
|
26
|
+
: (0, bibleBooks_1.parseVerseRange)(params.passageId).chapter;
|
|
27
|
+
return (firebase_1.firebaseUrl +
|
|
55
28
|
encodeURIComponent('audio_bibles' +
|
|
56
29
|
`/${params.bibleAudioId}` +
|
|
57
|
-
`/${
|
|
58
|
-
`/${
|
|
30
|
+
`/${book}` +
|
|
31
|
+
`/${book}_${chapter.padStart(3, '0')}.mp3`) +
|
|
59
32
|
`?alt=media`);
|
|
60
33
|
}
|
|
61
34
|
/** Extracts verses from a chapter based on verse numbers */
|
|
@@ -85,170 +58,119 @@ function extractVersesFromChapter(chapter, startVerse, endVerse) {
|
|
|
85
58
|
* ["GEN.1.1-GEN.1.25", "GEN.2.4-GEN.2.7", "EXO.3.3-EXO.3.25"] -> "Genesis 1: 1-25, 2: 4-7, Exodus 3: 3-25"
|
|
86
59
|
* ["JHN.1.1"] -> "John 1: 1"
|
|
87
60
|
*/
|
|
88
|
-
function getPassagesString(
|
|
89
|
-
if (!passageIds || passageIds.length === 0)
|
|
90
|
-
return '';
|
|
61
|
+
function getPassagesString(passages) {
|
|
91
62
|
const parts = [];
|
|
92
63
|
let currentBook = null;
|
|
93
|
-
for (const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// New book - include book name
|
|
106
|
-
if (currentBook !== startBook) {
|
|
107
|
-
currentBook = startBook;
|
|
108
|
-
// Same chapter
|
|
109
|
-
if (startChapter === endChapter) {
|
|
110
|
-
if (startVerse === endVerse) {
|
|
111
|
-
parts.push(`${bookName} ${startChapter}: ${startVerse}`);
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
parts.push(`${bookName} ${startChapter}: ${startVerse}-${endVerse}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
// Different chapters
|
|
119
|
-
parts.push(`${bookName} ${startChapter}: ${startVerse}-${endChapter}: ${endVerse}`);
|
|
120
|
-
}
|
|
64
|
+
for (const passage of passages) {
|
|
65
|
+
const bibleInfo = (0, bibles_1.getBibleInfo)(passage.bibleId);
|
|
66
|
+
if (!bibleInfo)
|
|
67
|
+
continue;
|
|
68
|
+
const { book, chapter, startVerse, endVerse } = (0, bibleBooks_1.parseVerseRange)(passage.passageId);
|
|
69
|
+
const bookName = bibleInfo.bookNames[book];
|
|
70
|
+
if (!bookName)
|
|
71
|
+
continue;
|
|
72
|
+
const verseRange = startVerse === endVerse ? startVerse : `${startVerse}-${endVerse}`;
|
|
73
|
+
if (currentBook !== book) {
|
|
74
|
+
currentBook = book;
|
|
75
|
+
parts.push((0, languages_1.numerals)(`${bookName} ${chapter}: ${verseRange}`, bibleInfo.language.script));
|
|
121
76
|
}
|
|
122
77
|
else {
|
|
123
|
-
|
|
124
|
-
if (startChapter === endChapter) {
|
|
125
|
-
if (startVerse === endVerse) {
|
|
126
|
-
parts.push(`${startChapter}: ${startVerse}`);
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
parts.push(`${startChapter}: ${startVerse}-${endVerse}`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
// Different chapters
|
|
134
|
-
parts.push(`${startChapter}: ${startVerse}-${endChapter}: ${endVerse}`);
|
|
135
|
-
}
|
|
78
|
+
parts.push((0, languages_1.numerals)(`${chapter}: ${verseRange}`, bibleInfo.language.script));
|
|
136
79
|
}
|
|
137
80
|
}
|
|
138
|
-
return
|
|
81
|
+
return parts.join(', ');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wraps a raw chapter fetcher with placeholder logic shared across all
|
|
85
|
+
* backends:
|
|
86
|
+
*
|
|
87
|
+
* - If the chapter is not in `availableTextChapters` nor
|
|
88
|
+
* `availableTimingsChapters`, synthesize a one-verse placeholder without
|
|
89
|
+
* calling the underlying fetcher.
|
|
90
|
+
* - If a fetched chapter is timings-only (verses exist but none have text), patch
|
|
91
|
+
* verse 1's text with `noTextAvailableString` so downstream consumers can
|
|
92
|
+
* render something.
|
|
93
|
+
*/
|
|
94
|
+
function withChapterPlaceholders(fetchRaw) {
|
|
95
|
+
return async ({ bibleId, chapterId, noTextAvailableString }) => {
|
|
96
|
+
const bibleInfo = (0, bibles_1.getBibleInfo)(bibleId);
|
|
97
|
+
if (!bibleInfo)
|
|
98
|
+
return undefined;
|
|
99
|
+
if (!bibleInfo.availableTextChapters.includes(chapterId) &&
|
|
100
|
+
!bibleInfo.availableTimingsChapters.includes(chapterId)) {
|
|
101
|
+
return {
|
|
102
|
+
bookName: bibleInfo.bookNames[chapterId.split('.')[0]],
|
|
103
|
+
chapterId,
|
|
104
|
+
reference: chapterId,
|
|
105
|
+
titles: null,
|
|
106
|
+
translationId: bibleId,
|
|
107
|
+
verses: [{ text: noTextAvailableString, verseId: `${chapterId}.1` }],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const chapter = await fetchRaw({ bibleId, chapterId });
|
|
111
|
+
if (!chapter)
|
|
112
|
+
return undefined;
|
|
113
|
+
if (chapter.verses.length > 0 && !chapter.verses.some((v) => v.text)) {
|
|
114
|
+
chapter.verses[0].text = noTextAvailableString;
|
|
115
|
+
}
|
|
116
|
+
return chapter;
|
|
117
|
+
};
|
|
139
118
|
}
|
|
140
119
|
/** Gets a scripture passage by extracting verses from chapters documents. */
|
|
141
|
-
async function getScripturePassage({ bibleId,
|
|
120
|
+
async function getScripturePassage({ bibleId, passageId, getChapter, noTextAvailableString, }) {
|
|
121
|
+
const bibleInfo = (0, bibles_1.getBibleInfo)(bibleId);
|
|
122
|
+
const { startVerse, endVerse, chapterId } = (0, bibleBooks_1.parseVerseRange)(passageId);
|
|
123
|
+
if (!bibleInfo)
|
|
124
|
+
return;
|
|
142
125
|
try {
|
|
143
|
-
const { startBook, startChapter, startVerse, endBook, endChapter, endVerse, } = parseVerseRange(passageId);
|
|
144
126
|
const startVerseNum = parseInt(startVerse);
|
|
145
127
|
const endVerseNum = parseInt(endVerse);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
console.warn(`No verses found for passage ${passageId}`);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
128
|
+
const chapter = await getChapter({
|
|
129
|
+
chapterId,
|
|
130
|
+
bibleId,
|
|
131
|
+
noTextAvailableString,
|
|
132
|
+
});
|
|
133
|
+
if (!chapter || chapter.verses.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
/**
|
|
136
|
+
* If we only have one verse for a chapter, it is the placeholder verse and
|
|
137
|
+
* we should return them as is instead of trying to extract a passage.
|
|
138
|
+
*/
|
|
139
|
+
if (chapter.verses.length === 1) {
|
|
161
140
|
return {
|
|
162
141
|
passageId,
|
|
163
|
-
bibleId,
|
|
164
|
-
|
|
165
|
-
verses,
|
|
142
|
+
bibleId: chapter.translationId,
|
|
143
|
+
verses: chapter.verses,
|
|
166
144
|
};
|
|
167
145
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (!chapter && bibleFallbackId)
|
|
178
|
-
chapter = await getChapter({ chapterId, bibleId: bibleFallbackId });
|
|
179
|
-
if (chapter) {
|
|
180
|
-
chapters.push(chapter);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
console.warn(`Missing chapter in range: ${bibleId}.${chapterId}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (chapters.length === 0) {
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
// Extract verses from each chapter
|
|
190
|
-
const allVerses = [];
|
|
191
|
-
chapters.forEach((chapter, index) => {
|
|
192
|
-
if (index === 0) {
|
|
193
|
-
// First chapter - from startVerse to end
|
|
194
|
-
const lastVerse = Math.max(...chapter.verses.map((v) => parseInt(v.verseId.split('.')[2])));
|
|
195
|
-
allVerses.push(...extractVersesFromChapter(chapter, startVerseNum, lastVerse));
|
|
196
|
-
}
|
|
197
|
-
else if (index === chapters.length - 1) {
|
|
198
|
-
// Last chapter - from beginning to endVerse
|
|
199
|
-
allVerses.push(...extractVersesFromChapter(chapter, 1, endVerseNum));
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
// Middle chapters - all verses
|
|
203
|
-
allVerses.push(...chapter.verses);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
return {
|
|
207
|
-
passageId,
|
|
208
|
-
bibleId,
|
|
209
|
-
header: getPassagesString([passageId], languageInfo),
|
|
210
|
-
verses: allVerses,
|
|
211
|
-
};
|
|
146
|
+
const verses = extractVersesFromChapter(chapter, startVerseNum, endVerseNum);
|
|
147
|
+
/**
|
|
148
|
+
* For textless chapters, verse 1 is always the placeholder verse. After
|
|
149
|
+
* extraction, we may have lost verse 1, so we patch back in the placeholder
|
|
150
|
+
* text.
|
|
151
|
+
*/
|
|
152
|
+
if (!verses.some((v) => v.text) && verses.length > 0)
|
|
153
|
+
verses[0].text = noTextAvailableString;
|
|
154
|
+
return { passageId, bibleId: chapter.translationId, verses };
|
|
212
155
|
}
|
|
213
156
|
catch (error) {
|
|
214
157
|
console.error(`Error getting scripture passage ${passageId} in ${bibleId}`, error);
|
|
215
|
-
|
|
158
|
+
throw error;
|
|
216
159
|
}
|
|
217
160
|
}
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
else if (snapshot.empty) {
|
|
233
|
-
console.warn('Empty snapshot for', bible);
|
|
234
|
-
return [];
|
|
235
|
-
}
|
|
236
|
-
for (const doc of snapshot.docs) {
|
|
237
|
-
const chapterParse = bibleChapters_1.BibleChapter.safeParse(doc.data());
|
|
238
|
-
if (!chapterParse.success) {
|
|
239
|
-
console.warn('Skipping invalid bible chapter document', doc.id, chapterParse.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`));
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
validChapters.push(chapterParse.data);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (validChapters.length === 0) {
|
|
246
|
-
console.warn('No valid chapters for', bible);
|
|
247
|
-
return [];
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
return validChapters;
|
|
251
|
-
}
|
|
161
|
+
/** Gets all scripture passages for a lesson. */
|
|
162
|
+
async function getLessonScripture({ getChapter, lessonInfo, noTextAvailableString, }) {
|
|
163
|
+
return Promise.all(lessonInfo.sections
|
|
164
|
+
.filter((s) => s.chapter === sets_1.Chapter.STORY)
|
|
165
|
+
.map((s) => {
|
|
166
|
+
const [bibleId, passageId] = s.id.split(';');
|
|
167
|
+
return getScripturePassage({
|
|
168
|
+
bibleId,
|
|
169
|
+
passageId,
|
|
170
|
+
getChapter,
|
|
171
|
+
noTextAvailableString,
|
|
172
|
+
});
|
|
173
|
+
}));
|
|
252
174
|
}
|
|
253
175
|
/**
|
|
254
176
|
* Converts a verse number to a superscript string. This is useful for
|
|
@@ -285,131 +207,123 @@ function verseToSuperscript(num) {
|
|
|
285
207
|
.join('');
|
|
286
208
|
}
|
|
287
209
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* produce one chunk per chapter, with isPartOfPrevious=true on the 2nd+ chunks.
|
|
291
|
-
* This mirrors leviathan's passage_ids_by_chapter splitting logic.
|
|
210
|
+
* Returns the FTB audio duration + afterFtb pause for a section, or 0 if the
|
|
211
|
+
* section has no FTB.
|
|
292
212
|
*/
|
|
293
|
-
function
|
|
294
|
-
if (
|
|
295
|
-
return
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const parts = verse.verseId.split('.');
|
|
300
|
-
const chapterId = `${parts[0]}.${parts[1]}`;
|
|
301
|
-
if (chapterId !== currentChapterId) {
|
|
302
|
-
chunks.push({
|
|
303
|
-
verses: [verse],
|
|
304
|
-
bookId: parts[0],
|
|
305
|
-
isPartOfPrevious: currentChapterId !== null,
|
|
306
|
-
});
|
|
307
|
-
currentChapterId = chapterId;
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
chunks[chunks.length - 1].verses.push(verse);
|
|
311
|
-
}
|
|
213
|
+
function getFtbDuration(section, lessonInfo) {
|
|
214
|
+
if (!section.ftbFileName)
|
|
215
|
+
return 0;
|
|
216
|
+
const ftbDuration = mediaDurations_1.mediaDurations[lessonInfo.contentLanguages.ftbs]?.[section.ftbFileName];
|
|
217
|
+
if (ftbDuration == null) {
|
|
218
|
+
console.warn(`FTB duration not found for ${section.ftbFileName}`);
|
|
312
219
|
}
|
|
313
|
-
return
|
|
220
|
+
return (ftbDuration ?? 0) + lessonInfo.lessonPauses.afterFtb;
|
|
314
221
|
}
|
|
315
222
|
/**
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
|
|
319
|
-
const alternativeLessonPauses = {
|
|
320
|
-
beforeStory: 1,
|
|
321
|
-
afterStory: 1,
|
|
322
|
-
betweenPassages: 0.5,
|
|
323
|
-
beforeFtb: 1,
|
|
324
|
-
afterFtb: 0.5,
|
|
325
|
-
};
|
|
326
|
-
/**
|
|
327
|
-
* List of languages whose lessons were built using slightly different pause
|
|
328
|
-
* values.
|
|
223
|
+
* Fills in `length` (for verse-timed story sections) and `startTime` (for all
|
|
224
|
+
* sections) by accumulating forward through the lesson. After this, every
|
|
225
|
+
* section has both fields set.
|
|
329
226
|
*/
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
227
|
+
function enrichSections(lessonInfo, scripture) {
|
|
228
|
+
const storySections = lessonInfo.sections.filter((s) => s.chapter === sets_1.Chapter.STORY);
|
|
229
|
+
/**
|
|
230
|
+
* Forward pass: compute lengths and start times for all non-application
|
|
231
|
+
* sections. We track whether any prior story had an unknown length — once
|
|
232
|
+
* that happens, every later story's startTime is unreliable (it accumulates
|
|
233
|
+
* from a bogus length), so we flag it with `ignoreTimings`.
|
|
234
|
+
*/
|
|
235
|
+
let currentTime = 0;
|
|
236
|
+
let priorStoryLengthUnknown = false;
|
|
237
|
+
const enriched = lessonInfo.sections.map((section) => {
|
|
238
|
+
if (!section.chapter)
|
|
239
|
+
return { ...section, startTime: 0, length: 0 };
|
|
240
|
+
currentTime += section.pauseBefore ?? 0;
|
|
241
|
+
let length;
|
|
242
|
+
const isStory = section.chapter === sets_1.Chapter.STORY;
|
|
243
|
+
const ignoreTimings = isStory && priorStoryLengthUnknown ? true : undefined;
|
|
244
|
+
const startTime = currentTime;
|
|
245
|
+
if (!isStory) {
|
|
246
|
+
length = mediaDurations_1.mediaDurations[section.languageId]?.[section.fileName];
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
currentTime += getFtbDuration(section, lessonInfo);
|
|
250
|
+
const [bibleId, passageId] = section.id.split(';');
|
|
251
|
+
length = bibleStatuses_1.bibleStatuses[bibleId]?.customPassages?.[passageId];
|
|
252
|
+
if (!length) {
|
|
253
|
+
const passage = scripture[storySections.indexOf(section)];
|
|
254
|
+
if (passage) {
|
|
255
|
+
const firstTimed = passage.verses.find((v) => v.timings);
|
|
256
|
+
const lastTimed = [...passage.verses].reverse().find((v) => v.timings);
|
|
257
|
+
if (firstTimed?.timings && lastTimed?.timings) {
|
|
258
|
+
length = lastTimed.timings[1] - firstTimed.timings[0];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (length == null)
|
|
263
|
+
priorStoryLengthUnknown = true;
|
|
264
|
+
}
|
|
265
|
+
if (length == null) {
|
|
266
|
+
console.warn(`Missing duration for section ${section.id} (${section.chapter}, ${section.fileName})`);
|
|
267
|
+
}
|
|
268
|
+
currentTime += length ?? 0;
|
|
269
|
+
return { ...section, length: length ?? 0, startTime, ignoreTimings };
|
|
270
|
+
});
|
|
271
|
+
// Backward pass: compute application section start times from the end of the
|
|
272
|
+
// lesson file, so they are always correct even if story durations are
|
|
273
|
+
// slightly off.
|
|
274
|
+
const fullFileName = lessonInfo.type === 'dbs'
|
|
275
|
+
? lessonInfo.full.localFileName
|
|
276
|
+
: lessonInfo.video.localFileName;
|
|
277
|
+
const totalDuration = mediaDurations_1.mediaDurations[lessonInfo.languageId]?.[fullFileName] ?? 0;
|
|
278
|
+
if (totalDuration > 0) {
|
|
279
|
+
let timeFromEnd = totalDuration;
|
|
280
|
+
const applicationSections = enriched.filter((s) => s.chapter === sets_1.Chapter.APPLICATION);
|
|
281
|
+
for (const section of [...applicationSections].reverse()) {
|
|
282
|
+
timeFromEnd -= section.length;
|
|
283
|
+
section.startTime = timeFromEnd;
|
|
284
|
+
timeFromEnd -= section.pauseBefore ?? 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return enriched;
|
|
336
288
|
}
|
|
337
289
|
/**
|
|
338
|
-
* Converts verse timings
|
|
339
|
-
*
|
|
340
|
-
* pauses, and from-the-book durations.
|
|
341
|
-
*
|
|
342
|
-
* Multi-chapter passages are split into per-chapter chunks internally, since
|
|
343
|
-
* the audio is clipped from individual chapter files.
|
|
290
|
+
* Converts verse timings from chapter-relative to lesson-relative using each
|
|
291
|
+
* section's `startTime` (set by {@link enrichSections}).
|
|
344
292
|
*/
|
|
345
|
-
function normalizeVerseTimings({
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
let cumulativeTime = lessonInfo.fellowshipDuration + pauses.beforeStory;
|
|
349
|
-
if (specialIds_1.specialIds.introductionLessonIds.includes(lessonInfo.lessonId) &&
|
|
350
|
-
lessonInfo.type === 'dbs' &&
|
|
351
|
-
lessonInfo.introLength)
|
|
352
|
-
cumulativeTime += lessonInfo.introLength;
|
|
353
|
-
let lastBook = null;
|
|
354
|
-
/** Tracks the overall passage index (not chunk index) for FTB/pause logic. */
|
|
355
|
-
let globalChunkIndex = 0;
|
|
356
|
-
return scripture?.map((passage) => {
|
|
293
|
+
function normalizeVerseTimings({ enrichedSections, scripture, lessonInfo, }) {
|
|
294
|
+
const storySections = enrichedSections.filter((s) => s.chapter === sets_1.Chapter.STORY);
|
|
295
|
+
return scripture.map((passage, passageIndex) => {
|
|
357
296
|
if (!passage)
|
|
358
297
|
return undefined;
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const ftbKey = `${ftbLanguage}.${chunk.bookId}.mp3`;
|
|
382
|
-
const ftbDuration = mediaDurations_1.mediaDurations[ftbLanguage]?.[ftbKey];
|
|
383
|
-
if (ftbDuration != null)
|
|
384
|
-
cumulativeTime += ftbDuration;
|
|
385
|
-
else {
|
|
386
|
-
console.error(`FTB duration not found for ${ftbKey}`);
|
|
387
|
-
return passage;
|
|
388
|
-
}
|
|
389
|
-
cumulativeTime += pauses.afterFtb;
|
|
390
|
-
lastBook = chunk.bookId;
|
|
391
|
-
}
|
|
392
|
-
else if (globalChunkIndex !== 0) {
|
|
393
|
-
cumulativeTime += pauses.betweenPassages;
|
|
394
|
-
}
|
|
395
|
-
globalChunkIndex++;
|
|
396
|
-
}
|
|
397
|
-
const offset = cumulativeTime - chunkAudioStart;
|
|
398
|
-
for (const verse of chunk.verses) {
|
|
298
|
+
const section = storySections[passageIndex];
|
|
299
|
+
const ignoreTimingsReturn = {
|
|
300
|
+
...passage,
|
|
301
|
+
verses: passage.verses.map((verse) => ({ ...verse, timings: null })),
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Section's startTime is wrong (e.g. an earlier story's scripture hasn't
|
|
305
|
+
* loaded), so applying it as an offset would produce bogus lesson-relative
|
|
306
|
+
* timings. Strip verse timings instead, which disables karaoke until the
|
|
307
|
+
* section becomes trusted.
|
|
308
|
+
*/
|
|
309
|
+
if (section.ignoreTimings)
|
|
310
|
+
return ignoreTimingsReturn;
|
|
311
|
+
const firstTimedVerse = passage?.verses.find((v) => v.timings);
|
|
312
|
+
if (!firstTimedVerse?.timings)
|
|
313
|
+
return ignoreTimingsReturn;
|
|
314
|
+
const offset = section.startTime +
|
|
315
|
+
getFtbDuration(section, lessonInfo) -
|
|
316
|
+
firstTimedVerse.timings[0];
|
|
317
|
+
return {
|
|
318
|
+
...passage,
|
|
319
|
+
verses: passage.verses.map((verse) => {
|
|
399
320
|
if (!verse.timings)
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
// Advance cumulative time by this chunk's audio duration
|
|
408
|
-
const lastTimedVerse = [...chunk.verses].reverse().find((v) => v.timings);
|
|
409
|
-
if (lastTimedVerse?.timings) {
|
|
410
|
-
cumulativeTime += lastTimedVerse.timings[1] - chunkAudioStart;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
return { ...passage, verses: adjustedVerses };
|
|
321
|
+
return verse;
|
|
322
|
+
return {
|
|
323
|
+
...verse,
|
|
324
|
+
timings: [verse.timings[0] + offset, verse.timings[1] + offset],
|
|
325
|
+
};
|
|
326
|
+
}),
|
|
327
|
+
};
|
|
414
328
|
});
|
|
415
329
|
}
|