152 lines
4.4 KiB
JavaScript
152 lines
4.4 KiB
JavaScript
// Helper functions for server-side rendering
|
|
function loadBooks(db) {
|
|
return new Promise((resolve, reject) => {
|
|
const query = 'SELECT id, folder_name, display_name, author FROM books ORDER BY display_name';
|
|
db.all(query, [], (err, rows) => {
|
|
if (err) {
|
|
console.error('Error loading books from database:', err.message);
|
|
resolve([]);
|
|
} else {
|
|
const books = rows.map(row => ({
|
|
id: row.id,
|
|
name: row.folder_name,
|
|
displayName: row.display_name || row.folder_name.replace(/-/g, ' '),
|
|
author: row.author
|
|
}));
|
|
resolve(books);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function loadChapters(db, bookName) {
|
|
return new Promise((resolve, reject) => {
|
|
const query = `
|
|
SELECT c.id, c.chapter_number, c.display_name, c.filename, b.folder_name
|
|
FROM chapters c
|
|
JOIN books b ON c.book_id = b.id
|
|
WHERE b.folder_name = ?
|
|
ORDER BY c.chapter_number
|
|
`;
|
|
db.all(query, [bookName], (err, rows) => {
|
|
if (err) {
|
|
console.error('Error loading chapters from database:', err.message);
|
|
resolve([]);
|
|
} else {
|
|
const chapters = rows.map(row => ({
|
|
id: row.id,
|
|
chapterNumber: row.chapter_number,
|
|
filename: row.filename,
|
|
displayName: row.display_name,
|
|
url: `/pdf/${row.folder_name}/${encodeURIComponent(row.filename)}`
|
|
}));
|
|
resolve(chapters);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Page Route handlers
|
|
async function homePage(db, req, res) {
|
|
try {
|
|
const books = await loadBooks(db);
|
|
res.render('index', {
|
|
title: 'Book Viewer',
|
|
books: books,
|
|
selectedBook: null,
|
|
selectedChapter: null,
|
|
chapters: []
|
|
});
|
|
} catch (error) {
|
|
console.error('Error loading books for home page:', error);
|
|
res.render('index', {
|
|
title: 'Book Viewer',
|
|
books: [],
|
|
selectedBook: null,
|
|
selectedChapter: null,
|
|
chapters: [],
|
|
error: 'Failed to load books'
|
|
});
|
|
}
|
|
}
|
|
|
|
async function bookPage(db, req, res) {
|
|
const bookName = req.params.bookName;
|
|
|
|
try {
|
|
const [books, chapters] = await Promise.all([
|
|
loadBooks(db),
|
|
loadChapters(db, bookName)
|
|
]);
|
|
const selectedBook = books.find(book => book.name === bookName);
|
|
|
|
if (!selectedBook) {
|
|
return res.redirect('/');
|
|
}
|
|
|
|
res.render('index', {
|
|
title: 'Book Viewer',
|
|
books: books,
|
|
selectedBook: selectedBook,
|
|
selectedChapter: null,
|
|
chapters: chapters
|
|
});
|
|
} catch (error) {
|
|
console.error('Error loading book page:', error);
|
|
res.redirect('/');
|
|
}
|
|
}
|
|
|
|
async function chapterPage(db, req, res) {
|
|
const bookName = req.params.bookName;
|
|
const chapterFile = decodeURIComponent(req.params.chapterFile);
|
|
|
|
try {
|
|
const [books, chapters] = await Promise.all([
|
|
loadBooks(db),
|
|
loadChapters(db, bookName)
|
|
]);
|
|
const selectedBook = books.find(book => book.name === bookName);
|
|
const selectedChapter = chapters.find(chapter => chapter.filename === chapterFile);
|
|
|
|
if (!selectedBook || !selectedChapter) {
|
|
return res.redirect('/');
|
|
}
|
|
|
|
res.render('index', {
|
|
title: 'Book Viewer',
|
|
books: books,
|
|
selectedBook: selectedBook,
|
|
selectedChapter: selectedChapter,
|
|
chapters: chapters
|
|
});
|
|
} catch (error) {
|
|
console.error('Error loading chapter page:', error);
|
|
res.redirect('/');
|
|
}
|
|
}
|
|
|
|
// Setup routes function
|
|
function setupRoutes(app, db) {
|
|
// Page Routes
|
|
app.get('/', async (req, res) => {
|
|
await homePage(db, req, res);
|
|
});
|
|
|
|
app.get('/book/:bookName', async (req, res) => {
|
|
await bookPage(db, req, res);
|
|
});
|
|
|
|
app.get('/book/:bookName/chapter/:chapterFile', async (req, res) => {
|
|
await chapterPage(db, req, res);
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
setupRoutes,
|
|
loadBooks,
|
|
loadChapters,
|
|
homePage,
|
|
bookPage,
|
|
chapterPage
|
|
}; |