thingamablog-v2/backend/server.js

122 lines
4.0 KiB
JavaScript

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}`);
});