// server.js // Usage: // 1) npm init -y // 2) npm install express multer better-sqlite3 // 3) node server.js // // Open: http://localhost:3000 const express = require('express'); const multer = require('multer'); const fs = require('fs'); const path = require('path'); const Database = require('better-sqlite3'); const PORT = process.env.PORT || 3000; const UPLOAD_DIR = path.join(__dirname, 'uploads'); if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true }); // Multer storage (safe filename) const storage = multer.diskStorage({ destination: (req, file, cb) => cb(null, UPLOAD_DIR), filename: (req, file, cb) => { const ext = path.extname(file.originalname).toLowerCase(); const safe = Date.now() + '-' + Math.round(Math.random()*1e9) + ext; cb(null, safe); } }); const upload = multer({ storage, limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB max (change if needed) fileFilter: (req, file, cb) => { // accept images only if (file.mimetype && file.mimetype.startsWith('image/')) cb(null, true); else cb(new Error('Seuls les fichiers image sont autorisés')); } }); const app = express(); // Init DB (SQLite) const db = new Database(path.join(__dirname, 'gallery.db')); db.pragma('journal_mode = WAL'); db.prepare(` CREATE TABLE IF NOT EXISTS photos ( id INTEGER PRIMARY KEY AUTOINCREMENT, given_name TEXT, filename TEXT NOT NULL, original_name TEXT, mime TEXT, size INTEGER, created_at TEXT NOT NULL ) `).run(); // Serve uploads statically app.use('/uploads', express.static(UPLOAD_DIR, { extensions: ['jpg','png','jpeg','gif','webp'] })); // Serve the single-page HTML app.get('/', (req, res) => { res.type('html').send(` Galerie simple

Ma Galerie Ultra simple





`); }); // Upload route app.post('/upload', upload.single('file'), (req, res) => { try { if (!req.file) return res.status(400).json({ message: 'Aucun fichier reçu' }); const givenName = (req.body.givenName || '').toString().trim(); const stmt = db.prepare(`INSERT INTO photos (given_name, filename, original_name, mime, size, created_at) VALUES (?, ?, ?, ?, ?, datetime('now'))`); stmt.run(givenName, req.file.filename, req.file.originalname, req.file.mimetype, req.file.size); return res.json({ ok: true, filename: req.file.filename }); } catch (err) { console.error(err); return res.status(500).json({ message: 'Erreur serveur' }); } }); // List route (returns all images, newest first) app.get('/list', (req, res) => { try { const rows = db.prepare('SELECT id, given_name, filename, original_name, mime, size, created_at FROM photos ORDER BY created_at DESC').all(); res.json({ items: rows }); } catch (err) { console.error(err); res.status(500).json({ message: 'Erreur DB' }); } }); // Simple health app.get('/ping', (req, res) => res.send('pong')); app.listen(PORT, () => { console.log('Server listening on http://localhost:' + PORT); });