const express = require('express'); const cors = require('cors'); const path = require('path'); const fs = require('fs'); const { parseHSQLDB } = require('./hsqldbParser'); const app = express(); const PORT = 3637; const DB_DIR = '/home/paulh/.openclaw/workspace/docs/pauls-blogs/Paul/database'; const EXPORT_FILE = path.join(__dirname, 'blog-export.json'); const IMAGE_DIR = '/home/paulh/.openclaw/workspace/docs/pauls-blogs/Paul/1096292361887/web'; app.use(cors()); // Serve blog images statically // Assuming image paths in blog posts are relative or absolute within the blog structure // We'll serve the specific blog's web folder at the root path or a specific prefix // Let's check a sample post content to see how images are referenced first app.use('/1096292361887/web', express.static(IMAGE_DIR)); // Also serve at root just in case paths are relative app.use('/', express.static(IMAGE_DIR)); let cachedEntries = []; let usingExport = false; // Load entries on startup try { if (fs.existsSync(EXPORT_FILE)) { console.log('Loading clean data from blog-export.json...'); const rawData = fs.readFileSync(EXPORT_FILE, 'utf8'); cachedEntries = JSON.parse(rawData); usingExport = true; console.log(`Successfully loaded ${cachedEntries.length} clean entries from JSON export.`); } else { console.log('No export file found, falling back to HSQLDB parser...'); cachedEntries = parseHSQLDB(DB_DIR); console.log(`Loaded ${cachedEntries.length} entries from HSQLDB (Legacy Parser)`); } } catch (err) { console.error('Failed to load database:', err.message); } // List all posts with minimal data app.get('/api/posts', (req, res) => { const items = cachedEntries.map((e, idx) => { if (usingExport) { return { id: e.id, title: e.title || 'Untitled', date: e.date || '', author: e.author || 'Paul', category: e.categories || '', }; } else { return { id: idx, title: e.TITLE || 'Untitled', date: e.TIMESTAMP || '', author: e.AUTHOR || 'Paul', category: e.CATEGORIES || '', }; } }); // Sort by date descending if using export (dates are cleaner) if (usingExport) { items.sort((a, b) => new Date(b.date) - new Date(a.date)); } res.json(items); }); // Get full data for one post app.get('/api/posts/:id', (req, res) => { const id = parseInt(req.params.id); let post = null; if (usingExport) { post = cachedEntries.find(p => p.id === id); } else { post = cachedEntries[id]; } if (!post) return res.status(404).json({error: 'Post not found.'}); if (usingExport) { // Fix old Windows file paths in image src attributes let body = post.content || ''; // Match: file:///\\paulspc2\...\Weblogs/FILENAME.jpg // Replace with: http://HOSTNAME:3637/FILENAME.jpg (full URL to backend) const hostname = req.get('host') || 'localhost:3637'; const protocol = req.protocol || 'http'; body = body.replace( /src="file:\/\/\/\\\\[^"]*[\\\/]([^\\\/]+\.(jpg|jpeg|png|gif))"/gi, `src="${protocol}://${hostname}/$1"` ); res.json({ title: post.title || 'Untitled', date: post.date || '', author: post.author || 'Paul', category: post.categories || '', body: body, draft: false, modified: '', }); } else { res.json({ title: post.TITLE || 'Untitled', date: post.TIMESTAMP || '', author: post.AUTHOR || 'Paul', category: post.CATEGORIES || '', body: post.ENTRY || '', draft: post.DRAFT || false, modified: post.MODIFIED || '', }); } }); app.listen(PORT, () => { console.log(`Thingamablog-v2 backend running on port ${PORT}`); });