Add support for multiple Bible translations

- Introduce configurable Bible version selection
- Modify content path handling to support version-specific subdirectories
- Update ESV API service to load Bible chapters from version-specific vault paths
- Enhance plugin initialization and settings to accommodate multiple translations
- Refactor content loading and rendering to use dynamic version paths
This commit is contained in:
Scott Tomaszewski 2025-03-10 16:37:23 -04:00
parent 35b4a27bb3
commit 1c5b21423d
3 changed files with 112 additions and 42 deletions

View file

@ -45,6 +45,7 @@ export default class DisciplesJournalPlugin extends Plugin {
// Configure services from settings
this.esvApiService.setApiToken(this.settings.esvApiToken);
this.esvApiService.setContentPath(this.settings.bibleContentVaultPath);
this.esvApiService.setBibleVersion(this.settings.preferredBibleVersion);
this.bibleContentService.setUseHtmlFormat(true);
this.bibleContentService.setDownloadOnDemand(this.settings.downloadOnDemand);
@ -55,12 +56,16 @@ export default class DisciplesJournalPlugin extends Plugin {
// Initialize components
this.bibleStyles = new BibleStyles(this.app);
// Create the full path with version for the renderer
const fullContentPath = `${this.settings.bibleContentVaultPath}/${this.settings.preferredBibleVersion}`;
this.bibleReferenceRenderer = new BibleReferenceRenderer(
this.app,
this.bibleContentService,
this.bookNameService,
this.settings.fontSizeForVerses,
this.settings.bibleContentVaultPath
fullContentPath
);
this.bibleReferenceRenderer.setDownloadOnDemand(this.settings.downloadOnDemand);
this.bibleReferenceParser = new BibleReferenceParser(this.bookNameService);
@ -123,6 +128,7 @@ export default class DisciplesJournalPlugin extends Plugin {
// Update services with new settings
this.esvApiService.setApiToken(this.settings.esvApiToken);
this.esvApiService.setContentPath(this.settings.bibleContentVaultPath);
this.esvApiService.setBibleVersion(this.settings.preferredBibleVersion);
this.bibleContentService.setDownloadOnDemand(this.settings.downloadOnDemand);
this.bibleReferenceRenderer.setDownloadOnDemand(this.settings.downloadOnDemand);
}
@ -132,7 +138,8 @@ export default class DisciplesJournalPlugin extends Plugin {
*/
async loadBibleData() {
try {
await this.bibleContentService.loadBible(null);
// Load Bible data from the appropriate version directory in the vault
await this.esvApiService.loadBibleChaptersFromVault();
} catch (error) {
console.error('Failed to load Bible data:', error);
}
@ -259,6 +266,13 @@ export default class DisciplesJournalPlugin extends Plugin {
}
}
/**
* Get the full path with version
*/
private getFullContentPath(): string {
return `${this.settings.bibleContentVaultPath}/${this.settings.preferredBibleVersion}`;
}
/**
* Open or create a chapter note
*/
@ -271,9 +285,9 @@ export default class DisciplesJournalPlugin extends Plugin {
return;
}
// Get content path
const contentPath = this.settings.bibleContentVaultPath;
const chapterPath = `${contentPath}/${parsedRef.book}/${parsedRef.book} ${parsedRef.chapter}.md`;
// Get full content path including version
const fullPath = this.getFullContentPath();
const chapterPath = `${fullPath}/${parsedRef.book}/${parsedRef.book} ${parsedRef.chapter}.md`;
// Check if note exists
const fileExists = await this.app.vault.adapter.exists(chapterPath);
@ -316,19 +330,16 @@ export default class DisciplesJournalPlugin extends Plugin {
// Use the formatter utility to format the content
const content = BibleFormatter.formatChapterContent(passage);
// Save the content to a note
const contentPath = this.settings.bibleContentVaultPath;
const bookPath = `${contentPath}/${reference.book}`;
const chapterPath = BibleFormatter.buildChapterPath(contentPath, reference.book, reference.chapter);
// Save the content to a note with the version path
const fullPath = this.getFullContentPath();
const bookPath = `${fullPath}/${reference.book}`;
const chapterPath = `${fullPath}/${reference.book}/${reference.book} ${reference.chapter}.md`;
// Create directory if needed
// Ensure the directory exists
await this.app.vault.adapter.mkdir(bookPath);
// Only create the file if it doesn't exist
const exists = await this.app.vault.adapter.exists(chapterPath);
if (!exists) {
await this.app.vault.create(chapterPath, content);
}
// Create the note
await this.app.vault.create(chapterPath, content);
return chapterPath;
} catch (error) {
@ -394,7 +405,20 @@ export default class DisciplesJournalPlugin extends Plugin {
*/
public setContentPath(path: string): void {
this.esvApiService.setContentPath(path);
this.bibleReferenceRenderer.setVaultPath(path);
// Pass the full path with version to the renderer for now
// This maintains backwards compatibility
const fullPath = `${path}/${this.settings.preferredBibleVersion}`;
this.bibleReferenceRenderer.setVaultPath(fullPath);
}
/**
* Set the preferred Bible version
*/
public setBibleVersion(version: string): void {
this.esvApiService.setBibleVersion(version);
// Update the renderer's path to include the version
const fullPath = `${this.settings.bibleContentVaultPath}/${version}`;
this.bibleReferenceRenderer.setVaultPath(fullPath);
}
/**

View file

@ -33,7 +33,8 @@ export interface ESVPassageMeta {
export class ESVApiService {
private app: App;
private apiToken: string = '';
private bibleContentVaultPath: string = 'Bible/ESV';
private bibleContentVaultPath: string = 'Bible'; // Root path for all Bible versions
private bibleVersion: string = 'ESV'; // Default version
private bookNameService: BookNameService;
// Store HTML formatted Bible chapters
@ -57,11 +58,25 @@ export class ESVApiService {
}
/**
* Set the path where Bible content will be stored in the vault
* Set the root path where Bible content will be stored in the vault
*/
public setContentPath(path: string): void {
this.bibleContentVaultPath = path;
}
/**
* Set the Bible version to use (affects the subdirectory)
*/
public setBibleVersion(version: string): void {
this.bibleVersion = version;
}
/**
* Get the full vault path including version subdirectory
*/
private getFullContentPath(): string {
return `${this.bibleContentVaultPath}/${this.bibleVersion}`;
}
/**
* Get HTML formatted Bible content from in-memory storage
@ -78,28 +93,56 @@ export class ESVApiService {
}
/**
* Load a collection of HTML formatted Bible chapters
* Load a collection of HTML formatted Bible chapters from files in the vault
*/
public loadChapterCollection(data: any): void {
if (!data) return;
public async loadBibleChaptersFromVault(): Promise<void> {
try {
// Process each chapter in the collection
for (const key in data) {
const chapterData = data[key];
if (this.isESVApiFormat(chapterData)) {
// Store the HTML content
const canonical = chapterData.canonical;
const htmlContent = chapterData.passages[0];
this.htmlFormattedBible[canonical] = {
canonical,
htmlContent
};
// Get the path where Bible content is stored
const fullPath = this.getFullContentPath();
// Check if path exists
if (!(await this.app.vault.adapter.exists(fullPath))) {
console.log(`Bible content directory ${fullPath} does not exist yet`);
return;
}
// Get all book directories
const bookDirs = await this.app.vault.adapter.list(fullPath);
// Process each book directory
for (const bookDir of bookDirs.folders) {
// Get all chapter files
const files = await this.app.vault.adapter.list(bookDir);
// Process each chapter file
for (const file of files.files) {
if (file.endsWith('.json')) {
try {
// Read and parse the file
const content = await this.app.vault.adapter.read(file);
const data = JSON.parse(content);
// Process the data if it's in the expected format
if (this.isESVApiFormat(data)) {
// Store the chapter content
const canonical = data.canonical;
const htmlContent = data.passages[0];
this.htmlFormattedBible[canonical] = {
canonical,
htmlContent
};
}
} catch (error) {
console.error(`Error processing file ${file}:`, error);
}
}
}
}
console.log(`Loaded ${Object.keys(this.htmlFormattedBible).length} Bible chapters from vault`);
} catch (error) {
console.error('Error loading chapter collection:', error);
console.error('Error loading Bible chapters from vault:', error);
}
}
@ -244,8 +287,10 @@ export class ESVApiService {
const chapter = parts[parts.length - 1];
const book = parts.slice(0, -1).join(' ');
// Create the directory structure
const bookPath = `${this.bibleContentVaultPath}/${book}`;
// Create the directory structure with version subdirectory
const fullPath = this.getFullContentPath();
const bookPath = `${fullPath}/${book}`;
await this.ensureVaultDirectoryExists(fullPath);
await this.ensureVaultDirectoryExists(bookPath);
// Save the raw API response as JSON

View file

@ -26,7 +26,7 @@ export const DEFAULT_SETTINGS: DisciplesJournalSettings = {
preferredBibleVersion: 'ESV',
esvApiToken: '',
downloadOnDemand: true,
bibleContentVaultPath: 'Bible/ESV'
bibleContentVaultPath: 'Bible'
};
export class DisciplesJournalSettingsTab extends PluginSettingTab {
@ -138,6 +138,7 @@ export class DisciplesJournalSettingsTab extends PluginSettingTab {
.onChange(async (value) => {
this.plugin.settings.preferredBibleVersion = value;
await this.plugin.saveSettings();
this.plugin.setBibleVersion(value);
})
);
@ -145,14 +146,14 @@ export class DisciplesJournalSettingsTab extends PluginSettingTab {
new Setting(containerEl)
.setName('Bible Content Vault Path')
.setDesc('Path in your vault where Bible content will be stored.')
.setDesc('Root path in your vault where Bible content will be stored. Each translation will be stored in a subdirectory.')
.addText(text => text
.setPlaceholder('Bible/ESV')
.setPlaceholder('Bible')
.setValue(this.plugin.settings.bibleContentVaultPath)
.onChange(async (value) => {
this.plugin.settings.bibleContentVaultPath = value || 'Bible/ESV';
this.plugin.settings.bibleContentVaultPath = value || 'Bible';
await this.plugin.saveSettings();
this.plugin.setContentPath(value || 'Bible/ESV');
this.plugin.setContentPath(value || 'Bible');
}));
containerEl.createEl('h3', { text: 'ESV API Settings' });