import express from 'express'; import multer from 'multer'; import path from 'path'; import fs from 'fs'; import { db, getConfig } from './db'; import { processUploadedImage } from './imageService'; export const galleryRouter = express.Router(); const upload = multer({ dest: path.join(__dirname, '../uploads/tmp') }); galleryRouter.get('/', (req, res) => { const catParam = req.query.cat ? Number(req.query.cat) : 0; const page = req.query.page ? Math.max(1, Number(req.query.page)) : 1; const config = getConfig(); const perPage = Number(config.albums_per_page) || 12; const categories = db.prepare('SELECT * FROM categories WHERE parent = ? ORDER BY pos ASC, name ASC').all(catParam) as any[]; const albCountRow = db.prepare('SELECT COUNT(*) as count FROM albums WHERE category = ?').get(catParam) as any; const totalAlbums = albCountRow ? albCountRow.count : 0; const totalPages = Math.ceil(totalAlbums / perPage) || 1; const offset = (page - 1) * perPage; const albums = db.prepare(` SELECT a.*, (SELECT COUNT(*) FROM pictures p WHERE p.aid = a.aid) as pic_count, (SELECT filename FROM pictures p WHERE p.aid = a.aid ORDER BY pid DESC LIMIT 1) as thumb_filename FROM albums a WHERE a.category = ? ORDER BY a.pos ASC, a.aid DESC LIMIT ? OFFSET ? `).all(catParam, perPage, offset) as any[]; const recentPics = db.prepare('SELECT * FROM pictures ORDER BY pid DESC LIMIT 8').all() as any[]; res.render('index', { title: config.gallery_name, description: config.gallery_description, categories, albums, recentPics, currentCat: catParam, page, totalPages, user: (req.session as any).user || null }); }); galleryRouter.get('/album/:aid', (req, res) => { const aid = Number(req.params.aid); const album = db.prepare('SELECT * FROM albums WHERE aid = ?').get(aid) as any; if (!album) { return res.status(404).render('message', { title: 'Not Found', message: 'Album does not exist.', backUrl: '/' }); } db.prepare('UPDATE albums SET alb_hits = alb_hits + 1 WHERE aid = ?').run(aid); const page = req.query.page ? Math.max(1, Number(req.query.page)) : 1; const config = getConfig(); const perPage = Number(config.pics_per_page) || 12; const picCountRow = db.prepare('SELECT COUNT(*) as count FROM pictures WHERE aid = ?').get(aid) as any; const totalPics = picCountRow ? picCountRow.count : 0; const totalPages = Math.ceil(totalPics / perPage) || 1; const offset = (page - 1) * perPage; const pictures = db.prepare('SELECT * FROM pictures WHERE aid = ? ORDER BY pid DESC LIMIT ? OFFSET ?').all(aid, perPage, offset) as any[]; res.render('album', { title: album.title, album, pictures, page, totalPages, user: (req.session as any).user || null }); }); galleryRouter.get('/picture/:pid', (req, res) => { const pid = Number(req.params.pid); const picture = db.prepare('SELECT * FROM pictures WHERE pid = ?').get(pid) as any; if (!picture) { return res.status(404).render('message', { title: 'Not Found', message: 'Picture does not exist.', backUrl: '/' }); } db.prepare('UPDATE pictures SET hits = hits + 1 WHERE pid = ?').run(pid); const album = db.prepare('SELECT * FROM albums WHERE aid = ?').get(picture.aid) as any; const comments = db.prepare('SELECT * FROM comments WHERE pid = ? ORDER BY msg_id ASC').all(pid) as any[]; const prevPic = db.prepare('SELECT pid FROM pictures WHERE aid = ? AND pid < ? ORDER BY pid DESC LIMIT 1').get(picture.aid, pid) as any; const nextPic = db.prepare('SELECT pid FROM pictures WHERE aid = ? AND pid > ? ORDER BY pid ASC LIMIT 1').get(picture.aid, pid) as any; res.render('displayimage', { title: picture.title || picture.filename, picture, album, comments, prevPid: prevPic ? prevPic.pid : null, nextPid: nextPic ? nextPic.pid : null, user: (req.session as any).user || null }); }); galleryRouter.post('/picture/:pid/comment', (req, res) => { const pid = Number(req.params.pid); const { msg_author, msg_body } = req.body; const user = (req.session as any).user; const authorName = user ? user.name : (msg_author || 'Guest'); const authorId = user ? user.id : 0; if (msg_body && msg_body.trim().length > 0) { db.prepare('INSERT INTO comments (pid, msg_author, msg_body, author_id) VALUES (?, ?, ?, ?)').run(pid, authorName, msg_body.trim(), authorId); } res.redirect(`/picture/${pid}`); }); galleryRouter.post('/picture/:pid/rate', (req, res) => { const pid = Number(req.params.pid); const rating = Math.min(5, Math.max(1, Number(req.body.rating) || 0)); if (rating > 0) { const pic = db.prepare('SELECT pic_rating, votes FROM pictures WHERE pid = ?').get(pid) as any; if (pic) { const newVotes = pic.votes + 1; const newRating = Math.round(((pic.pic_rating * pic.votes) + (rating * 2000)) / newVotes); db.prepare('UPDATE pictures SET pic_rating = ?, votes = ? WHERE pid = ?').run(newRating, newVotes, pid); } } res.redirect(`/picture/${pid}`); }); galleryRouter.get('/upload', (req, res) => { const user = (req.session as any).user; if (!user) { return res.redirect('/login'); } const albums = db.prepare('SELECT * FROM albums ORDER BY title ASC').all() as any[]; res.render('upload', { title: 'Upload File', albums, user }); }); galleryRouter.post('/upload', upload.single('userfile'), async (req, res) => { const user = (req.session as any).user; if (!user) { return res.redirect('/login'); } const { aid, title, caption, keywords } = req.body; if (!req.file || !aid) { return res.render('message', { title: 'Upload Failed', message: 'Please select an image file and target album.', backUrl: '/upload' }); } try { const ext = path.extname(req.file.originalname).toLowerCase(); const uniqueFilename = `${Date.now()}_${Math.floor(Math.random() * 10000)}${ext}`; const processed = await processUploadedImage(req.file.path, uniqueFilename); fs.unlinkSync(req.file.path); db.prepare(` INSERT INTO pictures (aid, filepath, filename, filesize, pwidth, pheight, owner_id, title, caption, keywords) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( Number(aid), processed.filepath, processed.filename, processed.filesize, processed.pwidth, processed.pheight, user.id, title || '', caption || '', keywords || '' ); res.redirect(`/album/${aid}`); } catch (err: any) { console.error('Upload Error:', err); res.render('message', { title: 'Upload Error', message: err.message || 'Failed to process uploaded file.', backUrl: '/upload' }); } });