Initial mvp-ish
This commit is contained in:
187
public/index.html
Normal file
187
public/index.html
Normal file
@@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ISBN Scanner</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2/dist/quagga.js"></script>
|
||||
<style>
|
||||
#interactive.viewport {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
overflow: hidden;
|
||||
}
|
||||
canvas.drawing, canvas.drawingBuffer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
#book-info {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Scan a Book ISBN</h1>
|
||||
<div>
|
||||
<label for="camera-select">Select Camera:</label>
|
||||
<select id="camera-select"></select>
|
||||
<button id="start-scanner">Start Scanner</button>
|
||||
</div>
|
||||
<div id="interactive" class="viewport"></div>
|
||||
<div>
|
||||
<h2>Or upload a barcode image</h2>
|
||||
<input type="file" id="barcode-input" accept="image/*">
|
||||
</div>
|
||||
<div id="book-info"></div>
|
||||
|
||||
<script>
|
||||
let selectedDeviceId;
|
||||
|
||||
async function testCameraAccess() {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
|
||||
console.log('Camera access granted', stream);
|
||||
} catch (error) {
|
||||
console.error('Error accessing camera:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get available video input devices (cameras)
|
||||
async function getCameras() {
|
||||
try {
|
||||
// Ensure the cameraSelect element is defined before accessing it
|
||||
const cameraSelect = document.getElementById('camera-select');
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ video: true }); // Prompt for camera access
|
||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||
const videoDevices = devices.filter(device => device.kind === 'videoinput');
|
||||
|
||||
// Update selectedDeviceId when user selects a camera
|
||||
cameraSelect.addEventListener('change', function() {
|
||||
selectedDeviceId = this.value;
|
||||
});
|
||||
if (videoDevices.length > 0) {
|
||||
videoDevices.forEach((device, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = device.deviceId;
|
||||
option.text = device.label || `Camera ${index + 1}`;
|
||||
cameraSelect.appendChild(option);
|
||||
});
|
||||
} else {
|
||||
console.log("No video devices found.");
|
||||
cameraSelect.innerHTML = '<option>No cameras found</option>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error accessing the camera or enumerating devices:", error);
|
||||
document.getElementById('camera-select').innerHTML = '<option>'+error+'</option>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function startScanner() {
|
||||
if (!selectedDeviceId) {
|
||||
alert('No camera selected or available.');
|
||||
return;
|
||||
}
|
||||
|
||||
Quagga.init({
|
||||
inputStream: {
|
||||
name: "Live",
|
||||
type: "LiveStream",
|
||||
target: document.querySelector('#interactive'),
|
||||
constraints: {
|
||||
deviceId: selectedDeviceId,
|
||||
facingMode: "environment", // Default to rear camera
|
||||
},
|
||||
},
|
||||
decoder: {
|
||||
readers: ["ean_reader"] // EAN is the standard format for ISBN-13 barcodes
|
||||
}
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
console.log("Initialization finished. Ready to start");
|
||||
Quagga.start();
|
||||
});
|
||||
|
||||
Quagga.onDetected(async function (data) {
|
||||
const isbn = data.codeResult.code;
|
||||
console.log("Detected ISBN:", isbn);
|
||||
Quagga.stop(); // Stop the scanner once an ISBN is detected
|
||||
|
||||
// Fetch book details
|
||||
fetchBookInfo(isbn);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchBookInfo(isbn) {
|
||||
fetch(`/book/${isbn}`)
|
||||
.then(response => response.json())
|
||||
.then(data => displayBookInfo(data))
|
||||
.catch(err => console.error('Error fetching book data:', err));
|
||||
}
|
||||
|
||||
function displayBookInfo(data) {
|
||||
const bookInfoDiv = document.getElementById('book-info');
|
||||
if (data.title) {
|
||||
bookInfoDiv.innerHTML = `
|
||||
<h2>${data.title}</h2>
|
||||
<p><strong>Authors:</strong> ${data.authors.join(', ')}</p>
|
||||
<p><strong>Published Date:</strong> ${data.publishedDate}</p>
|
||||
<p><strong>Description:</strong> ${data.description}</p>
|
||||
`;
|
||||
} else {
|
||||
bookInfoDiv.innerHTML = '<p>No book found for this ISBN.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle image file input
|
||||
document.getElementById('barcode-input').addEventListener('change', function(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const imageSrc = e.target.result;
|
||||
decodeBarcodeFromImage(imageSrc);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
|
||||
function decodeBarcodeFromImage(imageSrc) {
|
||||
Quagga.decodeSingle({
|
||||
src: imageSrc,
|
||||
numOfWorkers: 0, // Needs to be 0 when used with decodeSingle()
|
||||
inputStream: {
|
||||
size: 800 // Limit the size for better performance
|
||||
},
|
||||
decoder: {
|
||||
readers: ["ean_reader"] // EAN is the standard format for ISBN-13 barcodes
|
||||
}
|
||||
}, function(result) {
|
||||
if (result && result.codeResult) {
|
||||
console.log("Detected ISBN from image:", result.codeResult.code);
|
||||
fetchBookInfo(result.codeResult.code);
|
||||
} else {
|
||||
console.log("Barcode not detected in image.");
|
||||
document.getElementById('book-info').innerHTML = '<p>Barcode not detected in the image.</p>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Start the scanner when the start button is clicked
|
||||
document.getElementById('start-scanner').addEventListener('click', startScanner);
|
||||
|
||||
// Get cameras on page load
|
||||
window.onload = getCameras;
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user