diff --git a/books.db b/books.db index fa36490..018d634 100644 Binary files a/books.db and b/books.db differ diff --git a/index.js b/index.js index 35f0b58..a1479d9 100644 --- a/index.js +++ b/index.js @@ -61,14 +61,28 @@ app.get('/book/:isbn', async (req, res) => { // First 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}`]; + //Check for timeout or rate limit: + if(openLibraryResponse.status === 429){ + console.log('Rate limit exceeded'); + res.status(429).json({ error: 'Rate limit exceeded' }); + } + + if(openLibraryResponse.status === 408){ + console.log('Request Timeout'); + res.status(408).json({ error: 'Request Timeout' }); + } if (bookData) { console.log('Book data found in Open Library'); res.json(formatOpenLibraryData(bookData)); } else { + console.log('Book not found in Open Library'); + console.log('Trying Internet Archive...'); + // Fallback to Internet Archive if no data from Open Library const archiveResponse = await axios.get(`https://archive.org/advancedsearch.php?q=isbn:${isbn}&output=json`); const archiveData = archiveResponse.data; + console.log(archiveData); if (archiveData.response.numFound > 0) { res.json(formatArchiveData(archiveData.response.docs[0])); @@ -84,6 +98,39 @@ app.get('/book/:isbn', async (req, res) => { +// 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 diff --git a/public/index.html b/public/index.html index 22b5eaa..2ce849a 100644 --- a/public/index.html +++ b/public/index.html @@ -3,20 +3,20 @@ - ISBN Scanner + ISBN Scanner and Title Lookup -

Scan a Book ISBN

+

Scan a Book ISBN or Search by Title

-
-

Or upload a barcode image

- +

Or search for a book by title

+ +
@@ -27,11 +27,6 @@
-
- - - -
diff --git a/public/script.js b/public/script.js index 29bc8f0..9850042 100644 --- a/public/script.js +++ b/public/script.js @@ -21,6 +21,7 @@ async function getCameras() { // Update selectedDeviceId when user selects a camera cameraSelect.addEventListener('change', function() { selectedDeviceId = this.value; + startScanner(); }); if (videoDevices.length > 0) { @@ -53,11 +54,12 @@ function startScanner() { target: document.querySelector('#interactive'), constraints: { deviceId: selectedDeviceId, - facingMode: "environment", // Default to rear camera + facingMode: "environment", // Default to rear camera, + advanced: [{torch: true}] }, }, decoder: { - readers: ["ean_reader"] // EAN is the standard format for ISBN-13 barcodes + readers: ["ean_reader", "ean_8_reader", } }, function (err) { if (err) { @@ -66,6 +68,7 @@ function startScanner() { } console.log("Initialization finished. Ready to start"); Quagga.start(); + Quagga.CameraAccess.enableTorch(); }); Quagga.onDetected(async function (data) { @@ -122,6 +125,68 @@ function promptUserWithBook(bookData) { } } +// Add an event listener for the search button +document.getElementById('search-title').addEventListener('click', searchByTitle); + +async function searchByTitle() { + const title = document.getElementById('title-input').value; + if (!title) { + alert('Please enter a book title to search.'); + return; + } + + try { + const response = await fetch(`/search-title?title=${encodeURIComponent(title)}`); + const data = await response.json(); + + if (data.results && data.results.length > 0) { + displaySearchResults(data.results); + } else { + alert('No books found with that title.'); + } + } catch (error) { + console.error('Error searching for book by title:', error); + alert('An error occurred while searching for the book.'); + } +} + +function displaySearchResults(results) { + // Display the search results and allow the user to select one + const bookInfoDiv = document.getElementById('book-info'); + bookInfoDiv.innerHTML = ''; // Clear previous results + + results.forEach((book, index) => { + const bookElement = document.createElement('div'); + bookElement.innerHTML = ` +

Title: ${book.title}

+

Author(s): ${book.authors.join(', ')}

+

Published: ${book.publish_date || 'N/A'}

+

ISBN: ${book.isbn}

+

Publisher: ${book.publisher || 'N/A'}

+ + `; + bookInfoDiv.appendChild(bookElement); + }); + + // Store the results so that we can reference them when the user makes a selection + window.searchResults = results; +} + +function selectBook(index) { + const selectedBook = window.searchResults[index]; + console.log('Selected book:', selectedBook); + + // You can now fetch more details using the unique key if needed, or directly store this in your database + const isbn = selectedBook.isbn; + + if (isbn) { + fetchBookInfo(isbn); + } else { + promptUserWithBook(selectedBook); // You might have to adapt this if there's no ISBN + } +} + + async function storeBookInDatabase(bookData) { try { const response = await fetch('/store-book', { @@ -164,7 +229,7 @@ async function storeBookInDatabase(bookData) { // Start the scanner when the start button is clicked -document.getElementById('start-scanner').addEventListener('click', startScanner); +//document.getElementById('start-scanner').addEventListener('click', startScanner); // Get cameras on page load window.onload = getCameras; diff --git a/public/styles.css b/public/styles.css index 8496d2f..2cd6791 100644 --- a/public/styles.css +++ b/public/styles.css @@ -20,10 +20,6 @@ canvas.drawing, canvas.drawingBuffer { margin-top: 20px; } -#title-input { - display: none; -} - #prompt-message { font-weight: bold; }