UNPKG

express-quran-api

Version:

Simple Quran API with Express

163 lines (145 loc) 5.94 kB
const express = require('express'); const fs = require('fs'); const path = require('path'); class ExpressQuranAPI { constructor(options = {}) { this.app = express(); this.port = options.port || 3000; this.dataPath = options.dataPath || path.join(__dirname, 'data'); this.extraLanguages = options.extraLanguages || []; this.quranData = {}; this.cache = new Map(); this.searchIndex = new Map(); this.loadData(); this.buildSearchIndex(); this.setupRoutes(); } loadData() { const arPath = path.join(this.dataPath, 'quran_ar.json'); if (!fs.existsSync(arPath)) throw new Error('quran_ar.json not found! Please provide the Arabic Quran data file.'); this.quranData['ar'] = JSON.parse(fs.readFileSync(arPath, 'utf8')); this.extraLanguages.forEach(lang => { const filePath = path.join(this.dataPath, `quran_${lang}.json`); if (fs.existsSync(filePath)) { const langData = JSON.parse(fs.readFileSync(filePath, 'utf8')); langData.forEach((surah, sIdx) => { this.quranData['ar'][sIdx].translationName = this.quranData['ar'][sIdx].translationName || {}; this.quranData['ar'][sIdx].translationName[lang] = surah.translation || ''; surah.verses.forEach((ayah, aIdx) => { this.quranData['ar'][sIdx].verses[aIdx].translation = this.quranData['ar'][sIdx].verses[aIdx].translation || {}; this.quranData['ar'][sIdx].verses[aIdx].translation[lang] = ayah.translation || ''; }); }); } else { console.warn(`File for language "${lang}" not found: ${filePath}`); } }); } buildSearchIndex() { const data = this.quranData['ar']; data.forEach(surah => { surah.verses.forEach(ayah => { const words = ayah.text.replace(/[^\u0600-\u06FF\s]/g, '').split(/\s+/); words.forEach(word => { if (word.length > 0) { const cleanWord = word.trim(); if (!this.searchIndex.has(cleanWord)) { this.searchIndex.set(cleanWord, []); } this.searchIndex.get(cleanWord).push({ surah: surah.id, ayah: ayah.id, text: ayah.text }); } }); }); }); } setupRoutes() { const app = this.app; app.use(express.json({ limit: '1mb' })); app.get('/api/surahs', (req, res) => { const { filterType, type } = req.query; const cacheKey = `surahs_${filterType}_${type}`; if (this.cache.has(cacheKey)) { return res.json(this.cache.get(cacheKey)); } let surahs = JSON.parse(JSON.stringify(this.quranData['ar'])); if (filterType === 'true' && (type === 'meccan' || type === 'medinan')) { surahs = surahs.filter(s => s.type === type); } this.cache.set(cacheKey, surahs); res.json(surahs); }); app.get('/api/search', (req, res) => { const { q, lang } = req.query; if (!q) return res.status(400).json({ error: 'Query parameter "q" is required' }); const searchLang = lang || 'ar'; const cacheKey = `search_${q.toLowerCase()}_${searchLang}`; if (this.cache.has(cacheKey)) { return res.json(this.cache.get(cacheKey)); } const query = q.trim().replace(/[^\u0600-\u06FF\s]/g, ''); const results = []; if (searchLang === 'ar' && this.searchIndex.has(query)) { const indexResults = this.searchIndex.get(query); indexResults.forEach(item => { const surah = this.quranData['ar'].find(s => s.id === item.surah); const ayah = surah.verses.find(a => a.id === item.ayah); results.push({ surah: surah.id, surahName: surah.name, surahTranslation: surah.translationName?.[searchLang] || surah.translation || null, ayah: ayah.id, text: ayah.text, translation: (ayah.translation && ayah.translation[searchLang]) || null }); }); } else { const data = this.quranData['ar']; data.forEach(surah => { surah.verses.forEach(ayah => { const textMatch = ayah.text.toLowerCase().includes(q.toLowerCase()); const translationText = (ayah.translation && ayah.translation[searchLang]) || ''; const translationMatch = translationText.toLowerCase().includes(q.toLowerCase()); if (textMatch || translationMatch) { results.push({ surah: surah.id, surahName: surah.name, surahTranslation: surah.translationName?.[searchLang] || surah.translation || null, ayah: ayah.id, text: ayah.text, translation: translationText || null }); } }); }); } this.cache.set(cacheKey, results); res.json(results); }); app.get('/api/random', (req, res) => { const data = this.quranData['ar']; const surah = data[Math.floor(Math.random() * data.length)]; const ayah = surah.verses[Math.floor(Math.random() * surah.verses.length)]; const lang = req.query.lang || 'ar'; const translation = (ayah.translation && ayah.translation[lang]) || null; res.json({ surah: surah.id, surahName: surah.name, ayah: ayah.id, text: ayah.text, translation }); }); } listen(callback) { this.app.listen(this.port, () => { console.log('Express Quran API started on port ' + this.port); console.log('You can open the API in your browser at http://localhost:' + this.port); if (callback) callback(); }); } } module.exports = ExpressQuranAPI;