import { promises as fs } from 'fs'; import path from 'path'; import http from 'http'; import { fileURLToPath } from 'url'; // Get current directory name in ES modules const __dirname = path.dirname(fileURLToPath(import.meta.url)); async function generateSite() { try { // Check if images.json exists before trying to read it await fs.access('images.json', fs.constants.F_OK); // Read the images data const imagesData = JSON.parse( await fs.readFile('images.json', 'utf-8') ); console.log(imagesData); // Create output directory if it doesn't exist await fs.mkdir('public', { recursive: true }); // Copy the CSS file to public directory await fs.copyFile('public/styles.css', 'public/styles.css').catch(err => { console.error('Error copying CSS file:', err); }); // Copy the favicon await fs.copyFile('public/AnalogCameraS.png', 'public/favicon.png').catch(err => { console.error('Error copying favicon:', err); }); // Generate individual pages for each image for (let i = 0; i < imagesData.length; i++) { const image = imagesData[i]; const prevImage = imagesData[i > 0 ? i - 1 : imagesData.length - 1]; const nextImage = imagesData[(i + 1) % imagesData.length]; // Use image ID for filename const fileName = `${image.id}.html`; const prevFileName = `${prevImage.id}.html`; const nextFileName = `${nextImage.id}.html`; const html = ` ${image.description || `Image ${i + 1}`}
${image?.localPath ? `
${image.metadata.description || ''} ${image.metadata.description || ''}
` : '

Image not available

'} ${image.description ? `

${image.description}

` : ''}
`; await fs.writeFile(`public/${fileName}`, html); } // Update index.html to redirect to first image's ID const indexHtml = ` Redirecting... `; await fs.writeFile('public/index.html', indexHtml); console.log('Site generated successfully!'); } catch (error) { if (error.code === 'ENOENT') { console.error('images.json does not exist. Please run fetchImages.js first.'); } else { console.error('Error generating site:', error); } throw error; } } async function serveStaticSite(port = 3000) { const server = http.createServer(async (req, res) => { try { // Parse URL and query parameters const url = new URL(req.url, `http://localhost:${port}`); const quality = url.searchParams.get('quality'); const width = url.searchParams.get('width'); // Convert URL to filesystem path let filePath; if (url.pathname.startsWith('/images/')) { // Serve directly from images folder filePath = url.pathname.slice(1); // Remove leading slash console.log(`Request for image: ${filePath}`); console.log(`Parameters: quality=${quality}, width=${width}`); // If quality parameter is present, serve a resized version if (quality && width && /\.(jpe?g|png)$/i.test(filePath)) { // Case-insensitive check try { const Sharp = (await import('sharp')).default; // Get original image info const originalImage = await Sharp(filePath); const originalMetadata = await originalImage.metadata(); console.log('Original image metadata:', { width: originalMetadata.width, height: originalMetadata.height, size: originalMetadata.size, format: originalMetadata.format, orientation: originalMetadata.orientation }); // Process the image const processedImage = await Sharp(filePath) .rotate() .resize({ width: parseInt(width), height: parseInt(width), fit: 'inside' }) .jpeg({ quality: parseInt(quality), progressive: true, force: true // Force JPEG output regardless of input format }); // Get processed image info const processedMetadata = await processedImage.metadata(); console.log('Processed image metadata:', { width: processedMetadata.width, height: processedMetadata.height, format: processedMetadata.format }); // Convert to buffer and get size const buffer = await processedImage.toBuffer(); console.log('Processed image buffer size:', buffer.length); res.writeHead(200, { 'Content-Type': 'image/jpeg', 'Cache-Control': 'public, max-age=31536000', 'Content-Length': buffer.length }); res.end(buffer); return; } catch (error) { console.error('Error processing image:', error); // Fall through to serve original image } } else { // Log info for original image request console.log('Serving original image'); const stats = await fs.stat(filePath); console.log('Original file size:', stats.size); } } else { // Serve from public folder filePath = path.join('public', req.url === '/' ? 'index.html' : req.url); // Add .html extension if no extension exists if (!path.extname(filePath)) { filePath += '.html'; } } const content = await fs.readFile(filePath); // Set content type based on file extension const ext = path.extname(filePath).toLowerCase(); const contentType = { '.html': 'text/html', '.css': 'text/css', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif', }[ext] || 'application/octet-stream'; res.writeHead(200, { 'Content-Type': contentType }); res.end(content); } catch (error) { console.error('Error serving file:', error); res.writeHead(404); res.end('Not found'); } }); server.listen(port, () => { console.log(`Server running at http://localhost:${port}/`); }); } // Generate the site and then serve it generateSite() .then(() => serveStaticSite()) .catch(console.error);