commit 921a233c51ece5696e788d5c281e900c88c3f297 Author: Ryderjj89 Date: Sat Sep 13 11:58:52 2025 -0400 Initial setup for ESV Bible Markdown project diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..83dda369 --- /dev/null +++ b/.gitignore @@ -0,0 +1,67 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ + +# nyc test coverage +.nyc_output + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Docker +.dockerignore + +# Bible data (if not committed) +bible-data/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..7a18dbad --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM node:18-alpine + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci --only=production + +# Copy application code +COPY . . + +# Expose port +EXPOSE 3000 + +# Start the application +CMD ["npm", "start"] diff --git a/README.md b/README.md new file mode 100644 index 00000000..029c7292 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# ESV Bible Markdown + +A Docker-based web service for serving the ESV Bible in Markdown format. + +## Features + +- Complete ESV Bible text in Markdown format +- Docker containerized for easy deployment +- RESTful API for accessing Bible content +- Optimized for remote hosting + +## Setup + +1. Clone this repository +2. Place ESV Bible Markdown files in the `bible-data` directory +3. Run `docker-compose up --build` + +## Usage + +The service will be available at `http://localhost:3000` + +### API Endpoints + +- `GET /books` - List all books +- `GET /books/:book` - Get specific book +- `GET /books/:book/:chapter` - Get specific chapter + +## Development + +For local development: +```bash +npm install +npm run dev +``` + +## Docker Deployment + +Build and run with Docker Compose: +```bash +docker-compose up --build +``` + +## License + +MIT diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..bfaf6fd9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + esv-bible: + build: . + ports: + - "3000:3000" + volumes: + - ./bible-data:/app/bible-data:ro + environment: + - NODE_ENV=production + restart: unless-stopped diff --git a/package.json b/package.json new file mode 100644 index 00000000..e61e6f8f --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "esv-bible-markdown", + "version": "1.0.0", + "description": "ESV Bible in Markdown format served via Docker", + "main": "src/index.js", + "scripts": { + "start": "node src/index.js", + "dev": "nodemon src/index.js" + }, + "keywords": ["bible", "esv", "markdown", "docker"], + "author": "", + "license": "MIT", + "dependencies": { + "express": "^4.18.2", + "cors": "^2.8.5", + "helmet": "^7.1.0" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..7ec057a2 --- /dev/null +++ b/src/index.js @@ -0,0 +1,115 @@ +const express = require('express'); +const cors = require('cors'); +const helmet = require('helmet'); +const path = require('path'); +const fs = require('fs').promises; + +const app = express(); +const PORT = process.env.PORT || 3000; + +// Middleware +app.use(helmet()); +app.use(cors()); +app.use(express.json()); + +// Bible data directory +const BIBLE_DATA_DIR = path.join(__dirname, '../bible-data'); + +// Helper function to read markdown files +async function readMarkdownFile(filePath) { + try { + const content = await fs.readFile(filePath, 'utf-8'); + return content; + } catch (error) { + throw new Error(`Failed to read file: ${filePath}`); + } +} + +// Helper function to get all books +async function getBooks() { + try { + const files = await fs.readdir(BIBLE_DATA_DIR); + const markdownFiles = files.filter(file => file.endsWith('.md')); + return markdownFiles.map(file => file.replace('.md', '')); + } catch (error) { + throw new Error('Failed to read bible data directory'); + } +} + +// Routes +app.get('/health', (req, res) => { + res.json({ status: 'OK', message: 'ESV Bible API is running' }); +}); + +app.get('/books', async (req, res) => { + try { + const books = await getBooks(); + res.json({ books }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +app.get('/books/:book', async (req, res) => { + try { + const { book } = req.params; + const filePath = path.join(BIBLE_DATA_DIR, `${book}.md`); + + const content = await readMarkdownFile(filePath); + res.type('text/markdown').send(content); + } catch (error) { + res.status(404).json({ error: `Book '${req.params.book}' not found` }); + } +}); + +app.get('/books/:book/:chapter', async (req, res) => { + try { + const { book, chapter } = req.params; + const filePath = path.join(BIBLE_DATA_DIR, `${book}.md`); + + const content = await readMarkdownFile(filePath); + + // Simple chapter extraction (this could be improved with better parsing) + const lines = content.split('\n'); + const chapterPattern = new RegExp(`^# ${chapter}\\s*$`, 'i'); + const chapterLines = []; + let inChapter = false; + + for (const line of lines) { + if (chapterPattern.test(line)) { + inChapter = true; + chapterLines.push(line); + } else if (inChapter && line.startsWith('# ')) { + // Next chapter starts + break; + } else if (inChapter) { + chapterLines.push(line); + } + } + + if (chapterLines.length === 0) { + return res.status(404).json({ error: `Chapter ${chapter} not found in ${book}` }); + } + + res.type('text/markdown').send(chapterLines.join('\n')); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// Error handling middleware +app.use((err, req, res, next) => { + console.error(err.stack); + res.status(500).json({ error: 'Something went wrong!' }); +}); + +// 404 handler +app.use((req, res) => { + res.status(404).json({ error: 'Endpoint not found' }); +}); + +// Start server +app.listen(PORT, () => { + console.log(`ESV Bible API server running on port ${PORT}`); + console.log(`Bible data directory: ${BIBLE_DATA_DIR}`); +});