Files
biblical-guide.com/scripts/old/import-romanian-bible.ts
Andrei 95070e5369 Add comprehensive page management system to admin dashboard
Features added:
- Database schema for pages and media files with content types (Rich Text, HTML, Markdown)
- Admin API routes for full page CRUD operations
- Image upload functionality with file management
- Rich text editor using TinyMCE with image insertion
- Admin interface for creating/editing pages with SEO options
- Dynamic navigation and footer integration
- Public page display routes with proper SEO metadata
- Support for featured images and content excerpts

Admin features:
- Create/edit/delete pages with rich content editor
- Upload and manage images through media library
- Configure pages to appear in navigation or footer
- Set page status (Draft, Published, Archived)
- SEO title and description management
- Real-time preview of content changes

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 07:26:25 +00:00

378 lines
13 KiB
TypeScript

import { PrismaClient } from '@prisma/client'
import * as fs from 'fs'
import * as path from 'path'
import pdfParse from 'pdf-parse'
const prisma = new PrismaClient()
interface BibleVerse {
book: string
chapter: number
verse: number
text: string
}
interface BibleBook {
name: string
testament: string
orderNum: number
}
// Romanian Bible book names mapping
const romanianBooks: BibleBook[] = [
// Old Testament
{ name: 'Geneza', testament: 'Vechiul Testament', orderNum: 1 },
{ name: 'Exodul', testament: 'Vechiul Testament', orderNum: 2 },
{ name: 'Leviticul', testament: 'Vechiul Testament', orderNum: 3 },
{ name: 'Numerii', testament: 'Vechiul Testament', orderNum: 4 },
{ name: 'Deuteronomul', testament: 'Vechiul Testament', orderNum: 5 },
{ name: 'Iosua', testament: 'Vechiul Testament', orderNum: 6 },
{ name: 'Judecătorii', testament: 'Vechiul Testament', orderNum: 7 },
{ name: 'Rut', testament: 'Vechiul Testament', orderNum: 8 },
{ name: '1 Samuel', testament: 'Vechiul Testament', orderNum: 9 },
{ name: '2 Samuel', testament: 'Vechiul Testament', orderNum: 10 },
{ name: '1 Regi', testament: 'Vechiul Testament', orderNum: 11 },
{ name: '2 Regi', testament: 'Vechiul Testament', orderNum: 12 },
{ name: '1 Cronici', testament: 'Vechiul Testament', orderNum: 13 },
{ name: '2 Cronici', testament: 'Vechiul Testament', orderNum: 14 },
{ name: 'Ezra', testament: 'Vechiul Testament', orderNum: 15 },
{ name: 'Neemia', testament: 'Vechiul Testament', orderNum: 16 },
{ name: 'Estera', testament: 'Vechiul Testament', orderNum: 17 },
{ name: 'Iov', testament: 'Vechiul Testament', orderNum: 18 },
{ name: 'Psalmii', testament: 'Vechiul Testament', orderNum: 19 },
{ name: 'Proverbele', testament: 'Vechiul Testament', orderNum: 20 },
{ name: 'Ecleziastul', testament: 'Vechiul Testament', orderNum: 21 },
{ name: 'Cântarea Cântărilor', testament: 'Vechiul Testament', orderNum: 22 },
{ name: 'Isaia', testament: 'Vechiul Testament', orderNum: 23 },
{ name: 'Ieremia', testament: 'Vechiul Testament', orderNum: 24 },
{ name: 'Plângerile', testament: 'Vechiul Testament', orderNum: 25 },
{ name: 'Ezechiel', testament: 'Vechiul Testament', orderNum: 26 },
{ name: 'Daniel', testament: 'Vechiul Testament', orderNum: 27 },
{ name: 'Osea', testament: 'Vechiul Testament', orderNum: 28 },
{ name: 'Ioel', testament: 'Vechiul Testament', orderNum: 29 },
{ name: 'Amos', testament: 'Vechiul Testament', orderNum: 30 },
{ name: 'Obadia', testament: 'Vechiul Testament', orderNum: 31 },
{ name: 'Iona', testament: 'Vechiul Testament', orderNum: 32 },
{ name: 'Mica', testament: 'Vechiul Testament', orderNum: 33 },
{ name: 'Naum', testament: 'Vechiul Testament', orderNum: 34 },
{ name: 'Habacuc', testament: 'Vechiul Testament', orderNum: 35 },
{ name: 'Ţefania', testament: 'Vechiul Testament', orderNum: 36 },
{ name: 'Hagai', testament: 'Vechiul Testament', orderNum: 37 },
{ name: 'Zaharia', testament: 'Vechiul Testament', orderNum: 38 },
{ name: 'Maleahi', testament: 'Vechiul Testament', orderNum: 39 },
// New Testament
{ name: 'Matei', testament: 'Noul Testament', orderNum: 40 },
{ name: 'Marcu', testament: 'Noul Testament', orderNum: 41 },
{ name: 'Luca', testament: 'Noul Testament', orderNum: 42 },
{ name: 'Ioan', testament: 'Noul Testament', orderNum: 43 },
{ name: 'Faptele Apostolilor', testament: 'Noul Testament', orderNum: 44 },
{ name: 'Romani', testament: 'Noul Testament', orderNum: 45 },
{ name: '1 Corinteni', testament: 'Noul Testament', orderNum: 46 },
{ name: '2 Corinteni', testament: 'Noul Testament', orderNum: 47 },
{ name: 'Galateni', testament: 'Noul Testament', orderNum: 48 },
{ name: 'Efeseni', testament: 'Noul Testament', orderNum: 49 },
{ name: 'Filipeni', testament: 'Noul Testament', orderNum: 50 },
{ name: 'Coloseni', testament: 'Noul Testament', orderNum: 51 },
{ name: '1 Tesaloniceni', testament: 'Noul Testament', orderNum: 52 },
{ name: '2 Tesaloniceni', testament: 'Noul Testament', orderNum: 53 },
{ name: '1 Timotei', testament: 'Noul Testament', orderNum: 54 },
{ name: '2 Timotei', testament: 'Noul Testament', orderNum: 55 },
{ name: 'Tit', testament: 'Noul Testament', orderNum: 56 },
{ name: 'Filimon', testament: 'Noul Testament', orderNum: 57 },
{ name: 'Evrei', testament: 'Noul Testament', orderNum: 58 },
{ name: 'Iacob', testament: 'Noul Testament', orderNum: 59 },
{ name: '1 Petru', testament: 'Noul Testament', orderNum: 60 },
{ name: '2 Petru', testament: 'Noul Testament', orderNum: 61 },
{ name: '1 Ioan', testament: 'Noul Testament', orderNum: 62 },
{ name: '2 Ioan', testament: 'Noul Testament', orderNum: 63 },
{ name: '3 Ioan', testament: 'Noul Testament', orderNum: 64 },
{ name: 'Iuda', testament: 'Noul Testament', orderNum: 65 },
{ name: 'Apocalipsa', testament: 'Noul Testament', orderNum: 66 }
]
function parseRomanianBible(text: string): BibleVerse[] {
const verses: BibleVerse[] = []
// Remove common headers/footers and normalize text
const cleanText = text
.replace(/BIBLIA\s+FIDELA/gi, '')
.replace(/Copyright.*?România/gi, '')
.replace(/Cluj-Napoca.*?\d{4}/gi, '')
.replace(/\d+\s*$/gm, '') // Remove page numbers at end of lines
.replace(/\s+/g, ' ') // Normalize whitespace
.trim()
console.log('Cleaned text preview:', cleanText.substring(0, 2000))
// Look for patterns like "Geneza 1:1" or "1:1" with verse text
// First, split by book names to identify sections
const bookSections: { book: string, content: string }[] = []
let currentContent = cleanText
for (const book of romanianBooks) {
// Look for book name followed by chapter/verse patterns
const bookPattern = new RegExp(`\\b${book.name}\\b`, 'gi')
const bookMatch = currentContent.search(bookPattern)
if (bookMatch !== -1) {
// Extract content for this book (until next book or end)
let nextBookStart = currentContent.length
for (const nextBook of romanianBooks) {
if (nextBook.orderNum > book.orderNum) {
const nextPattern = new RegExp(`\\b${nextBook.name}\\b`, 'gi')
const nextMatch = currentContent.search(nextPattern)
if (nextMatch > bookMatch && nextMatch < nextBookStart) {
nextBookStart = nextMatch
}
}
}
const bookContent = currentContent.substring(bookMatch, nextBookStart)
bookSections.push({ book: book.name, content: bookContent })
}
}
console.log(`Found ${bookSections.length} book sections`)
// Parse each book section
for (const section of bookSections) {
console.log(`Parsing ${section.book}...`)
// Look for chapter:verse patterns like "1:1", "1:2", etc.
const versePattern = /(\d+):(\d+)\s+([^0-9:]+?)(?=\d+:\d+|$)/g
let match
while ((match = versePattern.exec(section.content)) !== null) {
const chapter = parseInt(match[1])
const verse = parseInt(match[2])
const text = match[3].trim()
// Clean up the verse text
const cleanVerseText = text
.replace(/\s+/g, ' ')
.replace(/^\W+|\W+$/g, '') // Remove leading/trailing non-word chars
.trim()
if (cleanVerseText.length > 5) { // Only keep substantial text
verses.push({
book: section.book,
chapter: chapter,
verse: verse,
text: cleanVerseText
})
}
}
// Alternative: look for numbered verses within paragraphs
const numberedVersePattern = /(\d+)\s+([^0-9]+?)(?=\d+\s+|$)/g
let altMatch
let currentChapter = 1
// Try to find chapter indicators
const chapterPattern = /Capitolul\s+(\d+)|^(\d+)$/gm
const chapterMatches = [...section.content.matchAll(chapterPattern)]
if (chapterMatches.length > 0) {
for (const chMatch of chapterMatches) {
currentChapter = parseInt(chMatch[1] || chMatch[2])
// Find content after this chapter marker
const chapterStart = chMatch.index! + chMatch[0].length
let chapterEnd = section.content.length
// Find next chapter marker
for (const nextChMatch of chapterMatches) {
if (nextChMatch.index! > chMatch.index! && nextChMatch.index! < chapterEnd) {
chapterEnd = nextChMatch.index!
}
}
const chapterContent = section.content.substring(chapterStart, chapterEnd)
// Parse verses in this chapter
while ((altMatch = numberedVersePattern.exec(chapterContent)) !== null) {
const verseNum = parseInt(altMatch[1])
const verseText = altMatch[2].trim()
const cleanText = verseText
.replace(/\s+/g, ' ')
.replace(/^\W+|\W+$/g, '')
.trim()
if (cleanText.length > 10) {
verses.push({
book: section.book,
chapter: currentChapter,
verse: verseNum,
text: cleanText
})
}
}
}
}
}
return verses
}
async function importRomanianBible() {
console.log('Starting Romanian Bible import...')
const pdfPath = path.join(process.cwd(), 'bibles', 'Biblia-Fidela-limba-romana.pdf')
if (!fs.existsSync(pdfPath)) {
throw new Error(`PDF file not found at: ${pdfPath}`)
}
console.log('Reading PDF file...')
const pdfBuffer = fs.readFileSync(pdfPath)
const pdfData = await pdfParse(pdfBuffer)
console.log(`PDF parsed. Text length: ${pdfData.text.length} characters`)
console.log('Parsing Bible verses...')
const verses = parseRomanianBible(pdfData.text)
console.log(`Found ${verses.length} verses`)
if (verses.length === 0) {
console.log('No verses found. PDF content preview:')
console.log(pdfData.text.substring(0, 1000))
throw new Error('Could not parse any verses from the PDF')
}
try {
// First, create all books
console.log('Creating Bible books...')
for (const bookData of romanianBooks) {
await prisma.bibleBook.upsert({
where: { id: bookData.orderNum },
update: {},
create: {
id: bookData.orderNum,
name: bookData.name,
testament: bookData.testament,
orderNum: bookData.orderNum
}
})
}
// Group verses by book and chapter
const versesByBook = verses.reduce((acc, verse) => {
if (!acc[verse.book]) acc[verse.book] = {}
if (!acc[verse.book][verse.chapter]) acc[verse.book][verse.chapter] = []
acc[verse.book][verse.chapter].push(verse)
return acc
}, {} as Record<string, Record<number, BibleVerse[]>>)
console.log('Importing verses by book and chapter...')
let totalImported = 0
for (const [bookName, chapters] of Object.entries(versesByBook)) {
const book = romanianBooks.find(b => b.name === bookName)
if (!book) {
console.warn(`Unknown book: ${bookName}`)
continue
}
console.log(`Importing ${bookName}...`)
for (const [chapterNumStr, chapterVerses] of Object.entries(chapters)) {
const chapterNum = parseInt(chapterNumStr)
// Create chapter
const chapter = await prisma.bibleChapter.upsert({
where: {
bookId_chapterNum: {
bookId: book.orderNum,
chapterNum: chapterNum
}
},
update: {},
create: {
bookId: book.orderNum,
chapterNum: chapterNum
}
})
// Create verses
for (const verse of chapterVerses) {
await prisma.bibleVerse.upsert({
where: {
chapterId_verseNum_version: {
chapterId: chapter.id,
verseNum: verse.verse,
version: 'RO'
}
},
update: {},
create: {
chapterId: chapter.id,
verseNum: verse.verse,
text: verse.text,
version: 'RO'
}
})
totalImported++
}
}
}
console.log(`Romanian Bible import completed! Imported ${totalImported} verses.`)
// Create search function
console.log('Creating search function...')
await prisma.$executeRaw`
CREATE OR REPLACE FUNCTION search_verses(search_query TEXT, limit_count INT DEFAULT 10)
RETURNS TABLE(
verse_id TEXT,
book_name TEXT,
chapter_num INT,
verse_num INT,
verse_text TEXT,
rank REAL
) AS $$
BEGIN
RETURN QUERY
SELECT
v.id::TEXT,
b.name,
c."chapterNum",
v."verseNum",
v.text,
CASE
WHEN v.text ILIKE '%' || search_query || '%' THEN 1.0
ELSE ts_rank(to_tsvector('romanian', v.text), plainto_tsquery('romanian', search_query))
END as rank
FROM "BibleVerse" v
JOIN "BibleChapter" c ON v."chapterId" = c.id
JOIN "BibleBook" b ON c."bookId" = b.id
WHERE v.text ILIKE '%' || search_query || '%'
OR to_tsvector('romanian', v.text) @@ plainto_tsquery('romanian', search_query)
ORDER BY rank DESC, b."orderNum", c."chapterNum", v."verseNum"
LIMIT limit_count;
END;
$$ LANGUAGE plpgsql;
`
console.log('Search function created successfully!')
} catch (error) {
console.error('Error importing Romanian Bible:', error)
throw error
}
}
// Run the import
importRomanianBible()
.then(() => {
console.log('Romanian Bible import completed successfully!')
process.exit(0)
})
.catch((error) => {
console.error('Import failed:', error)
process.exit(1)
})
.finally(() => prisma.$disconnect())