const axios = require('axios'); const express = require('express'); const https = require('https'); const fs = require('fs'); const path = require('path'); const sqlite3 = require('sqlite3').verbose(); const bodyParser = require('body-parser'); const app = express(); const PORT = process.env.PORT || 3000; // SSL certificate paths const privateKey = fs.readFileSync(path.join(__dirname, 'server.key'), 'utf8'); const certificate = fs.readFileSync(path.join(__dirname, 'server.cert'), 'utf8'); const credentials = { key: privateKey, cert: certificate }; // Middleware to parse JSON bodies app.use(express.json()); // Use built-in body-parser for JSON // Set up the SQLite database // Set up the SQLite database const db = new sqlite3.Database('./books.db', (err) => { if (err) { console.error('Could not connect to database', err); } else { console.log('Connected to database'); db.run(` CREATE TABLE IF NOT EXISTS books ( id INTEGER PRIMARY KEY AUTOINCREMENT, isbn TEXT, title TEXT, authors TEXT, publishedDate TEXT, description TEXT, url TEXT, number_of_pages INTEGER, identifiers TEXT, publishers TEXT, subjects TEXT, notes TEXT, cover_small TEXT, cover_medium TEXT, cover_large TEXT ) `); } }); // Serve static files from the 'public' directory app.use(express.static(path.join(__dirname, 'public'))); // Endpoint to fetch book details by ISBN // Endpoint to fetch book details by ISBN app.get('/book/:isbn', async (req, res) => { const { isbn } = req.params; console.log(`Fetching book data for ISBN: ${isbn}`); try { // First try Google Books const apiKey = 'AIzaSyCQikthZ5TlkFTcKTG8n171dRafosK2Mg8'; const googleBooksResponse = await axios.get(`https://www.googleapis.com/books/v1/volumes?q=${isbn}&key=${apiKey}`); if (googleBooksResponse.status === 429) { console.log('Rate limit exceeded for Google Books'); res.status(429).json({ error: 'Rate limit exceeded' }); return; } if (googleBooksResponse.status === 408) { console.log('Request Timeout for Google Books'); res.status(408).json({ error: 'Request Timeout' }); return; } if (googleBooksResponse.data.items && googleBooksResponse.data.items.length > 0) { const googleBookData = googleBooksResponse.data.items[0]; console.log('Book data found in Google Books'); res.json(formatGoogleBooksData(googleBookData)); return; } else { console.log('Book not found in Google Books'); } // If not found in Google Books, try Open Library const openLibraryResponse = await axios.get(`https://openlibrary.org/api/books?bibkeys=ISBN:${isbn}&format=json&jscmd=data`); const bookData = openLibraryResponse.data[`ISBN:${isbn}`]; if (openLibraryResponse.status === 429) { console.log('Rate limit exceeded for Open Library'); res.status(429).json({ error: 'Rate limit exceeded' }); return; } if (openLibraryResponse.status === 408) { console.log('Request Timeout for Open Library'); res.status(408).json({ error: 'Request Timeout' }); return; } if (bookData) { console.log('Book data found in Open Library'); res.json(formatOpenLibraryData(bookData)); return; } else { console.log('Book not found in Open Library'); } // If not found in Google Books or Open Library, try the Internet Archive const archiveResponse = await axios.get(`https://openlibrary.org/api/books?bibkeys=ISBN:${isbn}&format=json&jscmd=data`); const archiveData = archiveResponse.data[`ISBN:${isbn}`]; if (archiveData) { console.log('Book data found in the Internet Archive'); res.json(formatArchiveData(archiveData)); } else { console.log('Book not found in the Internet Archive'); res.status(404).json({ error: 'Book not found' }); } } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to fetch book data' }); } }); // Endpoint to search for book by title app.get('/search-title', async (req, res) => { const { title } = req.query; console.log(`Searching for book by title: ${title}`); try { // Search Open Library by title, limit to 5 results const openLibraryResponse = await axios.get(`https://openlibrary.org/search.json?q=${encodeURIComponent(title)}&limit=7`); const searchResults = openLibraryResponse.data.docs; console.log(searchResults); if (searchResults.length > 0) { console.log('Books found by title'); const bookData = searchResults.map(result => ({ title: result.title, authors: result.author_name || [], publish_date: result.first_publish_year, isbn: result.isbn ? result.isbn[0] : '', publisher: result.publisher ? result.publisher[0] : '', key: result.key // Unique key to fetch more detailed data later if needed })); console.log(bookData); res.json({ results: bookData }); } else { res.status(404).json({ error: 'No books found with that title.' }); } } catch (error) { console.error(error); res.status(500).json({ error: 'Failed to search for book by title' }); } }); // Endpoint to store book in the database // Endpoint to store book in the database // Endpoint to store book in the database app.post('/store-book', (req, res) => { const { isbn, title, authors, publishedDate, description, url, number_of_pages, identifiers, publishers, subjects, notes, cover_small, cover_medium, cover_large } = req.body; // Check if a book with the same ISBN already exists const checkQuery = `SELECT * FROM books WHERE isbn = ?`; db.get(checkQuery, [isbn], (err, row) => { if (err) { console.error('Error checking for existing book:', err); return res.status(500).json({ error: 'Failed to check for existing book' }); } if (row) { // Book already exists, update the existing record const updateQuery = ` UPDATE books SET title = ?, authors = ?, publishedDate = ?, description = ?, url = ?, number_of_pages = ?, identifiers = ?, publishers = ?, subjects = ?, notes = ?, cover_small = ?, cover_medium = ?, cover_large = ? WHERE isbn = ? `; const updateParams = [ title, authors ? authors.join(', ') : '', publishedDate, description || '', url, number_of_pages, identifiers, publishers, subjects, notes, cover_small, cover_medium, cover_large, isbn ]; db.run(updateQuery, updateParams, function (err) { if (err) { console.error('Error updating book in database:', err); return res.status(500).json({ error: 'Failed to update book in database' }); } else { res.json({ success: true, message: 'Book updated successfully' }); } }); } else { // Book does not exist, insert a new record const insertQuery = ` INSERT INTO books ( isbn, title, authors, publishedDate, description, url, number_of_pages, identifiers, publishers, subjects, notes, cover_small, cover_medium, cover_large ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `; const insertParams = [ isbn, title, authors ? authors.join(', ') : '', publishedDate, description || '', url, number_of_pages, identifiers, publishers, subjects, notes, cover_small, cover_medium, cover_large ]; db.run(insertQuery, insertParams, function (err) { if (err) { console.error('Error storing book in database:', err); return res.status(500).json({ error: 'Failed to store book in database' }); } else { res.json({ success: true, message: 'Book stored successfully', bookId: this.lastID }); } }); } }); }); function formatOpenLibraryData(data) { return { isbn: data.identifiers.isbn_13 ? data.identifiers.isbn_13[0] : '', title: data.title, authors: data.authors ? data.authors.map(author => author.name) : [], publishedDate: data.publish_date, description: data.excerpts ? data.excerpts[0].text : 'No description available', url: data.url, number_of_pages: data.number_of_pages || null, identifiers: JSON.stringify(data.identifiers), // Store as JSON string publishers: data.publishers ? data.publishers.map(pub => pub.name).join(', ') : '', subjects: data.subjects ? data.subjects.map(sub => sub.name).join(', ') : '', notes: data.notes || '', cover_small: data.cover ? data.cover.small : '', cover_medium: data.cover ? data.cover.medium : '', cover_large: data.cover ? data.cover.large : '' }; } function formatArchiveData(data) { return { isbn: data.isbn ? data.isbn[0] : '', title: data.title, authors: data.contributor ? [data.contributor] : [], publishedDate: data.date ? new Date(data.date).getFullYear() : '', description: data.description ? data.description.join(' ') : 'No description available', url: `https://archive.org/details/${data.identifier}`, number_of_pages: data.imagecount || null, identifiers: JSON.stringify({ archive_identifier: data.identifier, oclc: data['external-identifier'] ? data['external-identifier'].filter(id => id.includes('urn:oclc')).map(id => id.split(':')[2]) : [] }), publishers: data.publisher || '', subjects: data.subject ? data.subject.join(', ') : '', notes: '', // Archive data does not provide specific notes like Open Library cover_small: '', // Placeholder, as cover image URLs need to be constructed manually cover_medium: '', // Same as above cover_large: '' // Same as above }; } function formatGoogleBooksData(data) { return { isbn: data.volumeInfo.industryIdentifiers ? data.volumeInfo.industryIdentifiers.find(id => id.type === 'ISBN_13').identifier : '', title: data.volumeInfo.title, authors: data.volumeInfo.authors || [], publishedDate: data.volumeInfo.publishedDate, description: data.volumeInfo.description || 'No description available', url: data.volumeInfo.previewLink, number_of_pages: data.volumeInfo.pageCount || null, identifiers: JSON.stringify(data.volumeInfo.industryIdentifiers), publishers: data.volumeInfo.publisher || '', subjects: data.volumeInfo.categories || [], notes: '', // Placeholder for additional notes cover_small: data.volumeInfo.imageLinks.smallThumbnail || '', cover_medium: data.volumeInfo.imageLinks.thumbnail || '', cover_large: data.volumeInfo.imageLinks.small || '' }; } const httpsServer = https.createServer(credentials, app); httpsServer.listen(PORT, () => { console.log(`HTTPS Server running on https://localhost:${PORT}`); });